initial commit version 0.0.1

This commit is contained in:
louis
2014-09-27 09:25:14 +02:00
commit b0509b5182
503 changed files with 24368 additions and 0 deletions

174
libcore/fontmanager.c Normal file
View File

@@ -0,0 +1,174 @@
#include "fontmanager.h"
#include "../config.h"
#include <ft2build.h>
#include FT_FREETYPE_H
using namespace std;
cMutex cFontManager::mutex;
cFontManager::cFontManager() {
}
cFontManager::~cFontManager() {
DeleteFonts();
}
void cFontManager::CacheFonts(cTemplate *tpl) {
cMutexLock MutexLock(&mutex);
vector< pair<string, int> > usedFonts = tpl->GetUsedFonts();
cStringList availableFonts;
cFont::GetAvailableFontNames(&availableFonts);
for (vector< pair<string, int> >::iterator ft = usedFonts.begin(); ft != usedFonts.end(); ft++) {
string fontName = ft->first;
int fontSize = ft->second;
if (fontSize < 1) {
continue;
}
int fontAvailable = availableFonts.Find(fontName.c_str());
if (fontAvailable == -1) {
esyslog("skindesigner: font %s not available, skipping", fontName.c_str());
continue;
}
InsertFont(fontName, fontSize);
}
}
void cFontManager::Debug(void) {
dsyslog("skindesigner: fontmanager fonts available:");
for (map < string, map< int, cFont* > >::iterator fts = fonts.begin(); fts != fonts.end(); fts++) {
dsyslog("skindesigner: FontName %s", fts->first.c_str());
for (map<int, cFont*>::iterator ftSizes = (fts->second).begin(); ftSizes != (fts->second).end(); ftSizes++) {
int confHeight = ftSizes->first;
int realHeight = (ftSizes->second)->Height();
dsyslog("skindesigner: fontSize %d, fontHeight %d, ratio %f", confHeight, realHeight, (double)confHeight / (double)realHeight);
}
}
}
void cFontManager::ListAvailableFonts(void) {
cStringList availableFonts;
cFont::GetAvailableFontNames(&availableFonts);
int numFonts = availableFonts.Size();
esyslog("skindesigner: %d Fonts available:", numFonts);
for (int i=0; i<numFonts; i++) {
esyslog("skindesigner: font %d: %s", i, availableFonts[i]);
}
}
void cFontManager::DeleteFonts() {
cMutexLock MutexLock(&mutex);
for(map<string, map<int,cFont*> >::iterator it = fonts.begin(); it != fonts.end(); it++) {
for(map<int,cFont*>::iterator it2 = (it->second).begin(); it2 != (it->second).end(); it2++) {
delete it2->second;
}
}
fonts.clear();
}
int cFontManager::Width(string fontName, int fontSize, const char *text) {
cMutexLock MutexLock(&mutex);
if (!text)
return 0;
cFont *font = GetFont(fontName, fontSize);
//if not already cached, load it new
if (!font)
InsertFont(fontName, fontSize);
font = GetFont(fontName, fontSize);
if (!font)
return 0;
int width = font->Width(text);
return width;
}
int cFontManager::Height(string fontName, int fontSize) {
cMutexLock MutexLock(&mutex);
cFont *font = GetFont(fontName, fontSize);
//if not already cached, load it new
if (!font)
InsertFont(fontName, fontSize);
font = GetFont(fontName, fontSize);
if (!font)
return 0;
return font->Height();
}
cFont *cFontManager::Font(string fontName, int fontSize) {
cMutexLock MutexLock(&mutex);
cFont *font = GetFont(fontName, fontSize);
//if not already cached, load it new
if (!font)
InsertFont(fontName, fontSize);
font = GetFont(fontName, fontSize);
return font;
}
/********************************************************************************
* Private Functions
********************************************************************************/
cFont *cFontManager::CreateFont(string name, int size) {
cMutexLock MutexLock(&mutex);
cFont *fontTmp = cFont::CreateFont(name.c_str(), size);
if (!fontTmp)
fontTmp = cFont::CreateFont(Setup.FontOsd, size);
int realHeight = fontTmp->Height();
delete fontTmp;
cFont *font = cFont::CreateFont(name.c_str(), (double)size / (double)realHeight * (double)size);
if (!font)
font = cFont::CreateFont(Setup.FontOsd, (double)size / (double)realHeight * (double)size);
return font;
}
void cFontManager::InsertFont(string name, int size) {
cFont *newFont = CreateFont(name, size);
if (!newFont)
return;
map < string, map< int, cFont* > >::iterator hit = fonts.find(name);
if (hit != fonts.end()) {
(hit->second).insert(pair<int, cFont*>(size, newFont));
} else {
map<int, cFont*> fontsizes;
fontsizes.insert(pair<int, cFont*>(size, newFont));
fonts.insert(pair<string, map<int, cFont*> >(name, fontsizes));
}
}
cFont *cFontManager::GetFont(string name, int size) {
map< string, map<int,cFont*> >::iterator hitName = fonts.find(name);
if (hitName == fonts.end())
return NULL;
map<int,cFont*>::iterator hitSize = (hitName->second).find(size);
if (hitSize == (hitName->second).end())
return NULL;
return hitSize->second;
}
int cFontManager::GetFontHeight(const char *name, int height, int charWidth) {
FT_Library library;
FT_Face face;
cString fontFileName = cFont::GetFontFileName(name);
int descender = 0;
int y_ppem = 0;
int error = FT_Init_FreeType(&library);
if (error) return 0;
error = FT_New_Face(library, fontFileName, 0, &face);
if (error) return 0;
error = FT_Set_Char_Size(face, charWidth * 64, height * 64, 0, 0);
if (error) return 0;
descender = face->size->metrics.descender/64;
y_ppem = face->size->metrics.y_ppem;
int realHeight = y_ppem + descender;
FT_Done_Face(face);
FT_Done_FreeType(library);
return realHeight;
}

35
libcore/fontmanager.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef __FONTMANAGER_H
#define __FONTMANAGER_H
#include <string>
#include <map>
#include <vector>
#include <vdr/skins.h>
#include "../libtemplate/template.h"
using namespace std;
class cFontManager {
private:
static cMutex mutex;
map < string, map< int, cFont* > > fonts;
cFont *CreateFont(string name, int size);
void InsertFont(string name, int size);
cFont *GetFont(string name, int size);
int GetFontHeight(const char *name, int height, int charWidth = 0);
public:
cFontManager();
~cFontManager();
void Lock(void) { mutex.Lock(); };
void Unlock(void) { mutex.Unlock(); };
void CacheFonts(cTemplate *tpl);
void DeleteFonts(void);
int Width(string fontName, int fontSize, const char *text);
int Height(string fontName, int fontSize);
cFont *Font(string fontName, int fontSize);
void Debug(void);
void ListAvailableFonts(void);
};
#endif //__FONTMANAGER_H

155
libcore/helpers.c Normal file
View File

@@ -0,0 +1,155 @@
#include <string>
#include <sstream>
#include <vector>
#include "helpers.h"
#include <vdr/skins.h>
cPlugin *GetScraperPlugin(void) {
static cPlugin *pScraper = cPluginManager::GetPlugin("scraper2vdr");
if( !pScraper ) // if it doesn't exit, try tvscraper
pScraper = cPluginManager::GetPlugin("tvscraper");
return pScraper;
}
cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal) {
int width = 1;
int height = 1;
if ((widthMax == 0)||(heightMax==0)||(widthOriginal==0)||(heightOriginal==0))
return cSize(width, height);
if ((widthOriginal <= widthMax) && (heightOriginal <= heightMax)) {
width = widthOriginal;
height = heightOriginal;
} else if ((widthOriginal > widthMax) && (heightOriginal <= heightMax)) {
width = widthMax;
height = (double)width/(double)widthOriginal * heightOriginal;
} else if ((widthOriginal <= widthMax) && (heightOriginal > heightMax)) {
height = heightMax;
width = (double)height/(double)heightOriginal * widthOriginal;
} else {
width = widthMax;
height = (double)width/(double)widthOriginal * heightOriginal;
if (height > heightMax) {
height = heightMax;
width = (double)height/(double)heightOriginal * widthOriginal;
}
}
return cSize(width, height);
}
int Minimum(int a, int b, int c, int d, int e, int f) {
int min = a;
if (b < min) min = b;
if (c < min) min = c;
if (d < min) min = d;
if (e < min) min = e;
if (f < min) min = f;
return min;
}
string CutText(string &text, int width, string fontName, int fontSize) {
if (width <= fontManager->Font(fontName, fontSize)->Size())
return text.c_str();
cTextWrapper twText;
twText.Set(text.c_str(), fontManager->Font(fontName, fontSize), width);
string cuttedTextNative = twText.GetLine(0);
stringstream sstrText;
sstrText << cuttedTextNative << "...";
string cuttedText = sstrText.str();
int actWidth = fontManager->Width(fontName, fontSize, cuttedText.c_str());
if (actWidth > width) {
int overlap = actWidth - width;
int charWidth = fontManager->Width(fontName, fontSize, ".");
if (charWidth == 0)
charWidth = 1;
int cutChars = overlap / charWidth;
if (cutChars > 0) {
cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
stringstream sstrText2;
sstrText2 << cuttedTextNative << "...";
cuttedText = sstrText2.str();
}
}
return cuttedText;
}
string StrToLowerCase(string str) {
string lowerCase = str;
const int length = lowerCase.length();
for(int i=0; i < length; ++i) {
lowerCase[i] = std::tolower(lowerCase[i]);
}
return lowerCase;
}
bool isNumber(const string& s) {
string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
bool FileExists(const string &path, const string &name, const string &ext) {
stringstream fileName;
fileName << path << name << "." << ext;
struct stat buffer;
return (stat (fileName.str().c_str(), &buffer) == 0);
}
bool FirstFileInFolder(string &path, string &extension, string &fileName) {
DIR *folder = NULL;
struct dirent *file;
folder = opendir(path.c_str());
if (!folder)
return false;
while (file = readdir(folder)) {
if (endswith(file->d_name, extension.c_str())) {
string currentFileName = file->d_name;
int strlength = currentFileName.size();
if (strlength < 8)
continue;
fileName = currentFileName;
return true;
}
}
return false;
}
// split: receives a char delimiter; returns a vector of strings
// By default ignores repeated delimiters, unless argument rep == 1.
vector<string>& splitstring::split(char delim, int rep) {
if (!flds.empty()) flds.clear(); // empty vector if necessary
string work = data();
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;
}
cStopWatch::cStopWatch(void) {
start = cTimeMs::Now();
last = start;
}
void cStopWatch::Report(const char* message) {
dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - last));
last = cTimeMs::Now();
}
void cStopWatch::Stop(const char* message) {
dsyslog("skindesigner: %s - needed %d ms", message, (int)(cTimeMs::Now() - start));
}

35
libcore/helpers.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef __HELPERS_H
#define __HELPERS_H
#include <vdr/osd.h>
#include <vdr/plugin.h>
#include "../config.h"
cPlugin *GetScraperPlugin(void);
cSize ScaleToFit(int widthMax, int heightMax, int widthOriginal, int heightOriginal);
int Minimum(int a, int b, int c, int d, int e, int f);
std::string CutText(string &text, int width, string fontName, int fontSize);
std::string StrToLowerCase(string str);
bool isNumber(const string& s);
bool FileExists(const string &path, const string &name, const string &ext);
bool FirstFileInFolder(string &path, string &extension, string &fileName);
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);
};
class cStopWatch {
private:
uint64_t start;
uint64_t last;
public:
cStopWatch(void);
~cStopWatch(void) {};
void Report(const char* message);
void Stop(const char* message);
};
#endif // __HELPERS_H

389
libcore/imagecache.c Normal file
View File

@@ -0,0 +1,389 @@
#include <string>
#include <sstream>
#include <map>
#include <fstream>
#include <sys/stat.h>
#include "imagecache.h"
#include "../config.h"
#include "helpers.h"
using namespace Magick;
cMutex cImageCache::mutex;
string cImageCache::items[16] = { "Schedule", "Channels", "Timers", "Recordings", "Setup", "Commands",
"OSD", "EPG", "DVB", "LNB", "CAM", "Recording", "Replay", "Miscellaneous", "Plugins", "Restart"};
cImageCache::cImageCache() : cImageMagickWrapper() {
tempStaticLogo = NULL;
}
cImageCache::~cImageCache() {
Clear();
if (tempStaticLogo) {
delete tempStaticLogo;
tempStaticLogo = NULL;
}
}
void cImageCache::CacheLogo(int width, int height) {
if (config.numLogosPerSizeInitial == 0)
return;
if (width == 0 || height == 0)
return;
int channelsCached = 0;
for (const cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
if (channelsCached >= config.numLogosPerSizeInitial)
break;
if (channel->GroupSep()) {
continue;
}
bool success = LoadLogo(channel);
if (success) {
channelsCached++;
cImage *image = CreateImage(width, height);
stringstream logoName;
logoName << *channel->GetChannelID().ToString() << "_" << width << "x" << height;
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
if (hit != channelLogoCache.end()) {
delete image;
return;
}
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
}
}
}
cImage *cImageCache::GetLogo(string channelID, int width, int height) {
cMutexLock MutexLock(&mutex);
stringstream logoName;
logoName << channelID << "_" << width << "x" << height;
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
if (hit != channelLogoCache.end()) {
return (cImage*)hit->second;
} else {
tChannelID chanID = tChannelID::FromString(channelID.c_str());
const cChannel *channel = Channels.GetByChannelID(chanID);
if (!channel)
return NULL;
bool success = LoadLogo(channel);
if (success) {
if (config.limitLogoCache && (channelLogoCache.size() >= config.numLogosMax)) {
//logo cache is full, don't cache anymore
if (tempStaticLogo) {
delete tempStaticLogo;
tempStaticLogo = NULL;
}
tempStaticLogo = CreateImage(width, height);
return tempStaticLogo;
} else {
//add requested logo to cache
cImage *image = CreateImage(width, height);
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
hit = channelLogoCache.find(logoName.str());
if (hit != channelLogoCache.end()) {
return (cImage*)hit->second;
}
}
}
}
return NULL;
}
cImage *cImageCache::GetSeparatorLogo(string name, int width, int height) {
cMutexLock MutexLock(&mutex);
stringstream logoName;
logoName << name << "_" << width << "x" << height;
std::map<std::string, cImage*>::iterator hit = channelLogoCache.find(logoName.str());
if (hit != channelLogoCache.end()) {
return (cImage*)hit->second;
} else {
bool success = LoadSeparatorLogo(name);
if (success) {
//add requested logo to cache
cImage *image = CreateImage(width, height);
channelLogoCache.insert(pair<string, cImage*>(logoName.str(), image));
hit = channelLogoCache.find(logoName.str());
if (hit != channelLogoCache.end()) {
return (cImage*)hit->second;
}
}
}
return NULL;
}
bool cImageCache::LogoExists(string channelID) {
tChannelID chanID = tChannelID::FromString(channelID.c_str());
const cChannel *channel = Channels.GetByChannelID(chanID);
if (!channel)
return false;
string logoPath = *cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
string logoLower = StrToLowerCase(channel->Name());
string logoExt = *config.logoExtension;
bool logoExists = FileExists(logoPath, logoLower, logoExt);
if (logoExists) {
return true;
}
logoExists = FileExists(logoPath, channelID, logoExt);
if (logoExists) {
return true;
}
return false;
}
bool cImageCache::SeparatorLogoExists(string name) {
string separatorPath = *cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
string nameLower = StrToLowerCase(name.c_str());
string logoExt = *config.logoExtension;
bool logoExists = FileExists(separatorPath, nameLower, logoExt);
if (logoExists) {
return true;
}
return false;
}
void cImageCache::CacheIcon(eImageType type, string name, int width, int height) {
if (width < 1 || width > 1920 || height < 1 || height > 1080)
return;
bool success = LoadIcon(type, name);
if (!success)
return;
stringstream iconName;
iconName << name << "_" << width << "x" << height;
cImage *image = CreateImage(width, height, true);
iconCache.insert(pair<string, cImage*>(iconName.str(), image));
}
cImage *cImageCache::GetIcon(eImageType type, string name, int width, int height) {
if (width < 1 || width > 1920 || height < 1 || height > 1080)
return NULL;
cMutexLock MutexLock(&mutex);
stringstream iconName;
iconName << name << "_" << width << "x" << height;
map<string, cImage*>::iterator hit = iconCache.find(iconName.str());
if (hit != iconCache.end()) {
return (cImage*)hit->second;
} else {
bool success = LoadIcon(type, name);
if (!success)
return NULL;
cImage *image = CreateImage(width, height, true);
iconCache.insert(pair<string, cImage*>(iconName.str(), image));
hit = iconCache.find(iconName.str());
if (hit != iconCache.end()) {
return (cImage*)hit->second;
}
}
return NULL;
}
string cImageCache::GetIconName(string label) {
//check for standard menu entries
for (int i=0; i<16; i++) {
string s = trVDR(items[i].c_str());
if (s == label) {
return *cString::sprintf("standardicons/%s", items[i].c_str());
}
}
//check for special main menu entries "stop recording", "stop replay"
string stopRecording = skipspace(trVDR(" Stop recording "));
string stopReplay = skipspace(trVDR(" Stop replaying"));
try {
if (label.substr(0, stopRecording.size()) == stopRecording) {
return "standardicons/StopRecording";
}
if (label.substr(0, stopReplay.size()) == stopReplay) {
return "standardicons/StopReplay";
}
} catch (...) {}
//check for Plugins
for (int i = 0; ; i++) {
cPlugin *p = cPluginManager::GetPlugin(i);
if (p) {
const char *mainMenuEntry = p->MainMenuEntry();
if (mainMenuEntry) {
string plugMainEntry = mainMenuEntry;
try {
if (label.substr(0, plugMainEntry.size()) == plugMainEntry) {
return *cString::sprintf("pluginicons/%s", p->Name());
}
} catch (...) {}
}
} else
break;
}
return *cString::sprintf("customicons/%s", label.c_str());
}
void cImageCache::CacheSkinpart(string name, int width, int height) {
if (width < 1 || width > 1920 || height < 1 || height > 1080)
return;
bool success = LoadSkinpart(name);
if (!success)
return;
stringstream iconName;
iconName << name << "_" << width << "x" << height;
cImage *image = CreateImage(width, height, false);
skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
}
cImage *cImageCache::GetSkinpart(string name, int width, int height) {
if (width < 1 || width > 1920 || height < 1 || height > 1080)
return NULL;
cMutexLock MutexLock(&mutex);
stringstream iconName;
iconName << name << "_" << width << "x" << height;
map<string, cImage*>::iterator hit = skinPartsCache.find(iconName.str());
if (hit != skinPartsCache.end()) {
return (cImage*)hit->second;
} else {
bool success = LoadSkinpart(name);
if (!success)
return NULL;
cImage *image = CreateImage(width, height, false);
skinPartsCache.insert(pair<string, cImage*>(iconName.str(), image));
hit = skinPartsCache.find(iconName.str());
if (hit != skinPartsCache.end()) {
return (cImage*)hit->second;
}
}
return NULL;
}
bool cImageCache::LoadIcon(eImageType type, string name) {
bool success = false;
cString subdir("");
if (type == itMenuIcon)
subdir = "menuicons";
else if (type == itIcon)
subdir = "icons";
cString iconPath = cString::sprintf("%s%s/graphics/%s/", *config.skinPath, Setup.OSDTheme, *subdir);
success = LoadImage(name, *iconPath, "png");
if (success) {
return true;
}
return false;
}
bool cImageCache::LoadLogo(const cChannel *channel) {
if (!channel)
return false;
cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
string channelID = StrToLowerCase(*(channel->GetChannelID().ToString()));
string logoLower = StrToLowerCase(channel->Name());
bool success = false;
success = LoadImage(channelID.c_str(), *logoPath, *config.logoExtension);
if (success)
return true;
success = LoadImage(logoLower.c_str(), *logoPath, *config.logoExtension);
if (success)
return true;
return false;
}
bool cImageCache::LoadSeparatorLogo(string name) {
cString separatorPath = cString::sprintf("%s%s/logos/separatorlogos/", *config.skinPath, Setup.OSDTheme);
string nameLower = StrToLowerCase(name.c_str());
bool success = false;
success = LoadImage(nameLower.c_str(), *separatorPath, *config.logoExtension);
if (success)
return true;
return false;
}
bool cImageCache::LoadSkinpart(string name) {
bool success = false;
cString iconPath = cString::sprintf("%s%s/graphics/skinparts/", *config.skinPath, Setup.OSDTheme);
success = LoadImage(name, *iconPath, "png");
if (success) {
return true;
}
return false;
}
void cImageCache::Clear(void) {
for(map<string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
cImage *img = (cImage*)it->second;
delete img;
}
iconCache.clear();
for(map<string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
cImage *img = (cImage*)it->second;
delete img;
}
channelLogoCache.clear();
for(map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
cImage *img = (cImage*)it->second;
delete img;
}
skinPartsCache.clear();
}
void cImageCache::Debug(bool full) {
int sizeIconCache = 0;
int numIcons = 0;
GetIconCacheSize(numIcons, sizeIconCache);
dsyslog("skindesigner: cached %d icons - size %d byte", numIcons, sizeIconCache);
if (full) {
for(std::map<std::string, cImage*>::const_iterator it = iconCache.begin(); it != iconCache.end(); it++) {
string name = it->first;
dsyslog("skindesigner: cached icon %s", name.c_str());
}
}
int sizeLogoCache = 0;
int numLogos = 0;
GetLogoCacheSize(numLogos, sizeLogoCache);
dsyslog("skindesigner: cached %d logos - size %d byte", numLogos, sizeLogoCache);
if (full) {
for(std::map<std::string, cImage*>::const_iterator it = channelLogoCache.begin(); it != channelLogoCache.end(); it++) {
string name = it->first;
dsyslog("skindesigner: cached logo %s", name.c_str());
}
}
int sizeSkinpartCache = 0;
int numSkinparts = 0;
GetSkinpartsCacheSize(numSkinparts, sizeSkinpartCache);
dsyslog("skindesigner: cached %d skinparts - size %d byte", numSkinparts, sizeSkinpartCache);
if (full) {
for(std::map<std::string, cImage*>::const_iterator it = skinPartsCache.begin(); it != skinPartsCache.end(); it++) {
string name = it->first;
dsyslog("skindesigner: cached skinpart %s", name.c_str());
}
}
}
void cImageCache::GetIconCacheSize(int &num, int &size) {
num = iconCache.size();
for (map<string, cImage*>::iterator icon = iconCache.begin(); icon != iconCache.end(); icon++) {
cImage* img = icon->second;
size += img->Width() * img->Height() * sizeof(tColor);
}
}
void cImageCache::GetLogoCacheSize(int &num, int &size) {
num = channelLogoCache.size();
for (map<string, cImage*>::iterator logo = channelLogoCache.begin(); logo != channelLogoCache.end(); logo++) {
cImage* img = logo->second;
size += img->Width() * img->Height() * sizeof(tColor);
}
}
void cImageCache::GetSkinpartsCacheSize(int &num, int &size) {
num = skinPartsCache.size();
for (map<string, cImage*>::iterator skinpart = skinPartsCache.begin(); skinpart != skinPartsCache.end(); skinpart++) {
cImage* img = skinpart->second;
size += img->Width() * img->Height() * sizeof(tColor);
}
}

53
libcore/imagecache.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef __NOPACITY_IMAGECACHE_H
#define __NOPACITY_IMAGECACHE_H
#define X_DISPLAY_MISSING
#include <vdr/osd.h>
#include <vdr/skins.h>
#include <Magick++.h>
#include <vector>
#include "imagemagickwrapper.h"
#include "../libtemplate/templatefunction.h"
using namespace Magick;
class cImageCache : public cImageMagickWrapper {
public:
cImageCache();
~cImageCache();
void Lock(void) { mutex.Lock(); }
void Unlock(void) { mutex.Unlock(); }
//channel logos
void CacheLogo(int width, int height);
cImage *GetLogo(string channelID, int width, int height);
bool LogoExists(string channelID);
cImage *GetSeparatorLogo(string name, int width, int height);
bool SeparatorLogoExists(string name);
//icons
void CacheIcon(eImageType type, string path, int width, int height);
cImage *GetIcon(eImageType type, string name, int width, int height);
string GetIconName(string label);
//skinparts
void CacheSkinpart(string path, int width, int height);
cImage *GetSkinpart(string name, int width, int height);
//helpers
void Clear(void);
void Debug(bool full);
void GetIconCacheSize(int &num, int &size);
void GetLogoCacheSize(int &num, int &size);
void GetSkinpartsCacheSize(int &num, int &size);
private:
static cMutex mutex;
static string items[16];
cImage *tempStaticLogo;
map<string, cImage*> iconCache;
map<string, cImage*> channelLogoCache;
map<string, cImage*> skinPartsCache;
bool LoadIcon(eImageType type, string name);
bool LoadLogo(const cChannel *channel);
bool LoadSeparatorLogo(string name);
bool LoadSkinpart(string name);
};
#endif //__NOPACITY_IMAGECACHE_H

56
libcore/imageloader.c Normal file
View File

@@ -0,0 +1,56 @@
#include "../config.h"
#include "helpers.h"
#include "imageloader.h"
#include <math.h>
#include <string>
#include <dirent.h>
#include <iostream>
using namespace Magick;
cImageLoader::cImageLoader() : cImageMagickWrapper() {
}
cImageLoader::~cImageLoader() {
}
cImage cImageLoader::GetImage() {
return CreateImageCopy();
}
bool cImageLoader::LoadImage(const char *path, int width, int height) {
if (cImageMagickWrapper::LoadImage(path)) {
buffer.sample(Geometry(width, height));
return true;
}
return false;
}
void cImageLoader::DeterminateChannelLogoSize(int &width, int &height) {
cString logoPath = cString::sprintf("%s%s/logos/", *config.skinPath, Setup.OSDTheme);
cString logoExt = config.logoExtension;
DIR *folder = NULL;
struct dirent *file;
folder = opendir(logoPath);
if (!folder) {
return;
}
while (file = readdir(folder)) {
if (endswith(file->d_name, *logoExt)) {
std::stringstream filePath;
filePath << *logoPath << file->d_name;
Image logo;
try {
logo.read(filePath.str().c_str());
Geometry g = logo.size();
int logoWidth = g.width();
int logoHeight = g.height();
if (logoWidth > 0 && logoHeight > 0) {
width = logoWidth;
height = logoHeight;
return;
}
} catch( ... ) { }
}
}
}

23
libcore/imageloader.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef __NOPACITY_IMAGELOADER_H
#define __NOPACITY_IMAGELOADER_H
#define X_DISPLAY_MISSING
#include <vdr/osd.h>
#include <vdr/skins.h>
#include <Magick++.h>
#include "imagemagickwrapper.h"
using namespace Magick;
class cImageLoader : public cImageMagickWrapper {
public:
cImageLoader();
~cImageLoader();
cImage GetImage();
bool LoadImage(const char *path, int width, int height);
void DeterminateChannelLogoSize(int &width, int &height);
private:
};
#endif //__NOPACITY_IMAGELOADER_H

View File

@@ -0,0 +1,162 @@
#include <string>
#include <sstream>
#include "imagemagickwrapper.h"
#include "../config.h"
#include "imagescaler.h"
cImageMagickWrapper::cImageMagickWrapper() {
InitializeMagick(NULL);
}
cImageMagickWrapper::~cImageMagickWrapper() {
}
cImage *cImageMagickWrapper::CreateImage(int width, int height, bool preserveAspect) {
int w, h;
w = buffer.columns();
h = buffer.rows();
if (width == 0)
width = w;
if (height == 0)
height = h;
if (preserveAspect) {
unsigned scale_w = 1000 * width / w;
unsigned scale_h = 1000 * height / h;
if (scale_w > scale_h)
width = w * height / h;
else
height = h * width / w;
}
const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
cImage *image = new cImage(cSize(width, height));
tColor *imgData = (tColor *)image->Data();
if (w != width || h != height) {
ImageScaler scaler;
scaler.SetImageParameters(imgData, width, width, height, w, h);
for (const void *pixels_end = &pixels[w*h]; pixels < pixels_end; ++pixels)
scaler.PutSourcePixel(pixels->blue / ((MaxRGB + 1) / 256),
pixels->green / ((MaxRGB + 1) / 256),
pixels->red / ((MaxRGB + 1) / 256),
~((unsigned char)(pixels->opacity / ((MaxRGB + 1) / 256))));
return image;
}
for (const void *pixels_end = &pixels[width*height]; pixels < pixels_end; ++pixels)
*imgData++ = ((~int(pixels->opacity / ((MaxRGB + 1) / 256)) << 24) |
(int(pixels->green / ((MaxRGB + 1) / 256)) << 8) |
(int(pixels->red / ((MaxRGB + 1) / 256)) << 16) |
(int(pixels->blue / ((MaxRGB + 1) / 256)) ));
return image;
}
cImage cImageMagickWrapper::CreateImageCopy() {
int w, h;
w = buffer.columns();
h = buffer.rows();
cImage image (cSize(w, h));
const PixelPacket *pixels = buffer.getConstPixels(0, 0, w, h);
for (int iy = 0; iy < h; ++iy) {
for (int ix = 0; ix < w; ++ix) {
tColor col = (~int(pixels->opacity * 255 / MaxRGB) << 24)
| (int(pixels->green * 255 / MaxRGB) << 8)
| (int(pixels->red * 255 / MaxRGB) << 16)
| (int(pixels->blue * 255 / MaxRGB) );
image.SetPixel(cPoint(ix, iy), col);
++pixels;
}
}
return image;
}
bool cImageMagickWrapper::LoadImage(std::string FileName, std::string Path, std::string Extension) {
try {
std::stringstream sstrImgFile;
sstrImgFile << Path << FileName << "." << Extension;
std::string imgFile = sstrImgFile.str();
if (config.debugImageLoading)
dsyslog("skindesigner: trying to load: %s", imgFile.c_str());
buffer.read(imgFile.c_str());
if (config.debugImageLoading)
dsyslog("skindesigner: %s sucessfully loaded", imgFile.c_str());
} catch( Magick::Warning &warning ) {
if (config.debugImageLoading)
dsyslog("skindesigner: Magick Warning: %s", warning.what());
return true;
} catch( Magick::Error &error ) {
if (config.debugImageLoading)
dsyslog("skindesigner: Magick Error: %s", error.what());
return false;
} catch(...) {
if (config.debugImageLoading)
dsyslog("skindesigner: an unknown Magick error occured during image loading");
return false;
}
return true;
}
bool cImageMagickWrapper::LoadImage(const char *fullpath) {
if ((fullpath == NULL) || (strlen(fullpath) < 5))
return false;
try {
if (config.debugImageLoading)
dsyslog("skindesigner: trying to load: %s", fullpath);
buffer.read(fullpath);
if (config.debugImageLoading)
dsyslog("skindesigner: %s sucessfully loaded", fullpath);
} catch( Magick::Warning &warning ) {
if (config.debugImageLoading)
dsyslog("skindesigner: Magick Warning: %s", warning.what());
return true;
} catch( Magick::Error &error ) {
if (config.debugImageLoading)
dsyslog("skindesigner: Magick Error: %s", error.what());
return false;
} catch(...) {
if (config.debugImageLoading)
dsyslog("skindesigner: an unknown Magick error occured during image loading");
return false;
}
return true;
}
Color cImageMagickWrapper::Argb2Color(tColor col) {
tIndex alpha = (col & 0xFF000000) >> 24;
tIndex red = (col & 0x00FF0000) >> 16;
tIndex green = (col & 0x0000FF00) >> 8;
tIndex blue = (col & 0x000000FF);
Color color(MaxRGB*red/255, MaxRGB*green/255, MaxRGB*blue/255, MaxRGB*(0xFF-alpha)/255);
return color;
}
void cImageMagickWrapper::CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor) {
Color Back = Argb2Color(back);
Color Blend = Argb2Color(blend);
int maxw = MaxRGB * wfactor;
int maxh = MaxRGB * hfactor;
Image imgblend(Geometry(width, height), Blend);
imgblend.modifyImage();
imgblend.type(TrueColorMatteType);
PixelPacket *pixels = imgblend.getPixels(0, 0, width, height);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
PixelPacket *pixel = pixels + y * width + x;
int opacity = (maxw / width * x + maxh - maxh / height * y) / 2;
pixel->opacity = (opacity <= MaxRGB) ? opacity : MaxRGB;
}
}
imgblend.syncPixels();
Image imgback(Geometry(width, height), Back);
imgback.composite(imgblend, 0, 0, OverCompositeOp);
buffer = imgback;
}
void cImageMagickWrapper::CreateBackground(tColor back, tColor blend, int width, int height, bool mirror) {
CreateGradient(back, blend, width, height, 0.8, 0.8);
if (mirror)
buffer.flop();
}
void cImageMagickWrapper::CreateBackgroundReverse(tColor back, tColor blend, int width, int height) {
CreateGradient(back, blend, width, height, 1.3, 0.7);
}

View File

@@ -0,0 +1,28 @@
#ifndef __NOPACITY_IMAGEMAGICKWRAPPER_H
#define __NOPACITY_IMAGEMAGICKWRAPPER_H
#define X_DISPLAY_MISSING
#include <Magick++.h>
#include <vdr/osd.h>
using namespace Magick;
class cImageMagickWrapper {
private:
void CreateGradient(tColor back, tColor blend, int width, int height, double wfactor, double hfactor);
public:
cImageMagickWrapper();
~cImageMagickWrapper();
protected:
Image buffer;
Color Argb2Color(tColor col);
cImage *CreateImage(int width, int height, bool preserveAspect = true);
cImage CreateImageCopy(void);
bool LoadImage(std::string FileName, std::string Path, std::string Extension);
bool LoadImage(const char *fullpath);
void CreateBackground(tColor back, tColor blend, int width, int height, bool mirror = false);
void CreateBackgroundReverse(tColor back, tColor blend, int width, int height);
};
#endif //__NOPACITY_IMAGEMAGICKWRAPPER_H

149
libcore/imagescaler.c Normal file
View File

@@ -0,0 +1,149 @@
#include "imagescaler.h"
#include <cstdlib>
#include <cmath>
ImageScaler::ImageScaler() :
m_memory(NULL),
m_hor_filters(NULL),
m_ver_filters(NULL),
m_buffer(NULL),
m_dst_image(NULL),
m_dst_stride(0),
m_dst_width(0),
m_dst_height(0),
m_src_width(0),
m_src_height(0),
m_src_x(0),
m_src_y(0),
m_dst_x(0),
m_dst_y(0) {
}
ImageScaler::~ImageScaler() {
if ( m_memory ) free( m_memory );
}
// sin(x)/(x)
static float sincf( float x ) {
if ( fabsf(x) < 0.05f ) return 1.0f - (1.0f/6.0f)*x*x; // taylor series approximation to avoid 0/0
return sin(x)/x;
}
static void CalculateFilters( ImageScaler::Filter *filters, int dst_size, int src_size ) {
const float fc = dst_size >= src_size ? 1.0f : ((float) dst_size)/((float) src_size);
for (int i = 0; i < dst_size; i++) {
const int d = 2*dst_size; // sample position denominator
const int e = (2*i+1) * src_size - dst_size; // sample position enumerator
int offset = e / d; // truncated sample position
const float sub_offset = ((float) (e - offset*d)) / ((float) d); // exact sample position is (float) e/d = offset + sub_offset
// calculate filter coefficients
float h[4];
for (int j=0; j<4; j++) {
const float t = 3.14159265359f * (sub_offset+(1-j));
h[j] = sincf( fc * t ) * cosf( 0.25f * t ); // sinc-lowpass and cos-window
}
// ensure that filter does not reach out off image bounds:
while ( offset < 1 ) {
h[0] += h[1];
h[1] = h[2];
h[2] = h[3];
h[3] = 0.0f;
offset++;
}
while ( offset+3 > src_size ) {
h[3] += h[2];
h[2] = h[1];
h[1] = h[0];
h[0] = 0.0f;
offset--;
}
// coefficients are normalized to sum up to 2048
const float norm = 2048.0f / ( h[0] + h[1] + h[2] + h[3] );
offset--; // offset of fist used pixel
filters[i].m_offset = offset + 4; // store offset of first unused pixel
for (int j=0; j<4; j++) {
const float t = norm * h[j];
filters[i].m_coeff[(offset+j) & 3] = (int) ((t > 0.0f) ? (t+0.5f) : (t-0.5f)); // consider ring buffer index permutations
}
}
// set end marker
filters[dst_size].m_offset = (unsigned) -1;
}
void ImageScaler::SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height ) {
m_src_x = 0;
m_src_y = 0;
m_dst_x = 0;
m_dst_y = 0;
m_dst_image = dst_image;
m_dst_stride = dst_stride;
// if image dimensions do not change we can keep the old filter coefficients
if ( (src_width == m_src_width) && (src_height == m_src_height) && (dst_width == m_dst_width) && (dst_height == m_dst_height) ) return;
m_dst_width = dst_width;
m_dst_height = dst_height;
m_src_width = src_width;
m_src_height = src_height;
if ( m_memory ) free( m_memory );
const unsigned hor_filters_size = (m_dst_width + 1) * sizeof(Filter); // reserve one extra position for end marker
const unsigned ver_filters_size = (m_dst_height + 1) * sizeof(Filter);
const unsigned buffer_size = 4 * m_dst_width * sizeof(TmpPixel);
char *p = (char *) malloc( hor_filters_size + ver_filters_size + buffer_size );
m_memory = p;
m_hor_filters = (Filter *) p; p += hor_filters_size;
m_ver_filters = (Filter *) p; p += ver_filters_size;
m_buffer = (TmpPixel *) p;
CalculateFilters( m_hor_filters, m_dst_width , m_src_width );
CalculateFilters( m_ver_filters, m_dst_height, m_src_height );
}
// shift range to 0..255 and clamp overflows
static unsigned shift_clamp( int x ) {
x = ( x + (1<<21) ) >> 22;
if ( x < 0 ) return 0;
if ( x > 255 ) return 255;
return x;
}
void ImageScaler::NextSourceLine() {
m_dst_x = 0;
m_src_x = 0;
m_src_y++;
while ( m_ver_filters[m_dst_y].m_offset == m_src_y ) {
const int h0 = m_ver_filters[m_dst_y].m_coeff[0];
const int h1 = m_ver_filters[m_dst_y].m_coeff[1];
const int h2 = m_ver_filters[m_dst_y].m_coeff[2];
const int h3 = m_ver_filters[m_dst_y].m_coeff[3];
const TmpPixel *src = m_buffer;
unsigned *dst = m_dst_image + m_dst_stride * m_dst_y;
for (unsigned i=0; i<m_dst_width; i++) {
const ImageScaler::TmpPixel t( src[0]*h0 + src[1]*h1 + src[2]*h2 + src[3]*h3 );
src += 4;
dst[i] = shift_clamp(t[0]) | (shift_clamp(t[1])<<8) | (shift_clamp(t[2])<<16) | (shift_clamp(t[3])<<24);
}
m_dst_y++;
}
}

97
libcore/imagescaler.h Normal file
View File

@@ -0,0 +1,97 @@
#ifndef _ImageScaler_h
#define _ImageScaler_h
/*!
* this class scales images consisting of 4 components (RGBA)
* to an arbitrary size using a 4-tap filter
*/
class ImageScaler {
public:
struct Filter {
unsigned m_offset;
short m_coeff[4];
};
ImageScaler();
~ImageScaler();
//! set destination image and source image size
void SetImageParameters( unsigned *dst_image, unsigned dst_stride, unsigned dst_width, unsigned dst_height, unsigned src_width, unsigned src_height );
/*! process one pixel of source image; destination image is written while input is processed
* SetImageParameters() must be called first
*/
void PutSourcePixel( unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3 ) {
m_hbuf[ (m_src_x++) & 3 ].Set( c0, c1, c2, c3 );
TmpPixel *bp = m_buffer + 4 * m_dst_x + (m_src_y & 3);
const Filter *fh;
while ( (fh=m_hor_filters+m_dst_x)->m_offset == m_src_x ) {
*bp = m_hbuf[0]*fh->m_coeff[0] + m_hbuf[1]*fh->m_coeff[1] + m_hbuf[2]*fh->m_coeff[2] + m_hbuf[3]*fh->m_coeff[3];
m_dst_x++;
bp += 4;
}
if ( m_src_x == m_src_width ) NextSourceLine();
}
private:
//! temporary image pixel class - a 4-element integer vector
class TmpPixel {
public:
TmpPixel() {
}
TmpPixel( int c0, int c1, int c2, int c3 ) {
Set(c0,c1,c2,c3);
}
void Set( int c0, int c1, int c2, int c3 ) {
m_comp[0] = c0;
m_comp[1] = c1;
m_comp[2] = c2;
m_comp[3] = c3;
}
TmpPixel operator*( int s ) const {
return TmpPixel( m_comp[0]*s, m_comp[1]*s, m_comp[2]*s, m_comp[3]*s );
}
TmpPixel operator+( const TmpPixel &x ) const {
return TmpPixel( m_comp[0] + x[0], m_comp[1] + x[1], m_comp[2] + x[2], m_comp[3] + x[3] );
}
// return component i=[0..3] - No range check!
int operator[](unsigned i) const {
return m_comp[i];
}
private:
int m_comp[4];
};
//! this is called whenever one input line is processed completely
void NextSourceLine();
TmpPixel m_hbuf[4]; //! ring buffer for 4 input pixels
char *m_memory; //! buffer container
Filter *m_hor_filters; //! buffer for horizontal filters (one for each output image column)
Filter *m_ver_filters; //! buffer for vertical filters (one for each output image row)
TmpPixel *m_buffer; //! buffer contains 4 horizontally filtered input lines, multiplexed
unsigned *m_dst_image; //! pointer to destination image
unsigned m_dst_stride; //! destination image stride
unsigned m_dst_width; //! destination image width
unsigned m_dst_height; //! destination image height
unsigned m_src_width; //! source image width
unsigned m_src_height; //! source image height
unsigned m_src_x; //! x position of next source image pixel
unsigned m_src_y; //! y position of source image line currently beeing processed
unsigned m_dst_x; //! x position of next destination image pixel
unsigned m_dst_y; //! x position of next destination image line
};
#endif // _ImageScaler_h

477
libcore/pixmapcontainer.c Normal file
View File

@@ -0,0 +1,477 @@
#define __STL_CONFIG_H
#include "pixmapcontainer.h"
#include "../config.h"
cMutex cPixmapContainer::mutex;
cOsd *cPixmapContainer::osd = NULL;
eFlushState cPixmapContainer::flushState = fsOpen;
cPixmapContainer::cPixmapContainer(int numPixmaps) {
this->numPixmaps = numPixmaps;
pixContainerInit = true;
mutex.Lock();
pixmaps = new cPixmap*[numPixmaps];
pixmapsTransparency = new int[numPixmaps];
for(int i=0; i < numPixmaps; i++) {
pixmaps[i] = NULL;
pixmapsTransparency[i] = 0;
}
mutex.Unlock();
checkRunning = false;
fadeTime = 0;
deleteOsdOnExit = false;
}
cPixmapContainer::~cPixmapContainer(void) {
for (int i=0; i < numPixmaps; i++) {
mutex.Lock();
if (pixmaps[i] && osd) {
osd->DestroyPixmap(pixmaps[i]);
pixmaps[i] = NULL;
}
mutex.Unlock();
}
delete[] pixmaps;
delete[] pixmapsTransparency;
if (deleteOsdOnExit && osd) {
mutex.Lock();
delete osd;
osd = NULL;
mutex.Unlock();
}
}
bool cPixmapContainer::CreateOsd(int Left, int Top, int Width, int Height) {
if (osd) {
return true;
}
cOsd *newOsd = cOsdProvider::NewOsd(Left, Top);
if (newOsd) {
tArea Area = { 0, 0, Width, Height, 32 };
if (newOsd->SetAreas(&Area, 1) == oeOk) {
osd = newOsd;
return true;
}
}
return false;
}
void cPixmapContainer::LockFlush(void) {
flushState = fsLock;
}
void cPixmapContainer::OpenFlush(void) {
flushState = fsOpen;
}
bool cPixmapContainer::PixmapExists(int num) {
cMutexLock MutexLock(&mutex);
if (pixmaps[num])
return true;
return false;
}
void cPixmapContainer::DoFlush(void) {
cMutexLock MutexLock(&mutex);
if (!osd || (checkRunning && !Running()))
return;
if (flushState == fsOpen) {
osd->Flush();
}
}
void cPixmapContainer::CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort) {
cMutexLock MutexLock(&mutex);
if (!osd || (checkRunning && !Running()))
return;
pixmaps[num] = osd->CreatePixmap(Layer, ViewPort, DrawPort);
pixmaps[num]->Fill(clrTransparent);
if (pixContainerInit && fadeTime) {
pixmaps[num]->SetAlpha(0);
} else if (pixmapsTransparency[num] > 0) {
int alpha = (100 - pixmapsTransparency[num])*255/100;
pixmaps[num]->SetAlpha(alpha);
}
}
bool cPixmapContainer::DestroyPixmap(int num) {
cMutexLock MutexLock(&mutex);
if (pixmaps[num] && osd) {
osd->DestroyPixmap(pixmaps[num]);
pixmaps[num] = NULL;
return true;
}
return false;
}
void cPixmapContainer::DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
fontManager->Lock();
cFont *font = fontManager->Font(fontName, fontSize);
if (font)
pixmaps[num]->DrawText(Point, s, ColorFg, ColorBg, font);
fontManager->Unlock();
}
void cPixmapContainer::DrawRectangle(int num, const cRect &Rect, tColor Color) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->DrawRectangle(Rect, Color);
}
void cPixmapContainer::DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->DrawEllipse(Rect, Color, Quadrants);
}
void cPixmapContainer::DrawImage(int num, const cPoint &Point, const cImage &Image) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->DrawImage(Point, Image);
}
void cPixmapContainer::DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool Overlay) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->DrawBitmap(Point, Bitmap, ColorFg, ColorBg, Overlay);
}
void cPixmapContainer::Fill(int num, tColor Color) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->Fill(Color);
}
void cPixmapContainer::SetAlpha(int num, int Alpha) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->SetAlpha(Alpha);
}
void cPixmapContainer::SetTransparency(int num, int Transparency) {
if (Transparency < 0 && Transparency > 100)
return;
pixmapsTransparency[num] = Transparency;
}
void cPixmapContainer::SetLayer(int num, int Layer) {
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->SetLayer(Layer);
}
int cPixmapContainer::Width(int num) {
if (checkRunning && !Running())
return 0;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return 0;
int width = pixmaps[num]->ViewPort().Width();
return width;
}
int cPixmapContainer::Height(int num) {
if (checkRunning && !Running())
return 0;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return 0;
int height = pixmaps[num]->ViewPort().Height();
return height;
}
int cPixmapContainer::DrawportWidth(int num) {
if (checkRunning && !Running())
return 0;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return 0;
int width = pixmaps[num]->DrawPort().Width();
return width;
}
int cPixmapContainer::DrawportHeight(int num) {
if (checkRunning && !Running())
return 0;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return 0;
int height = pixmaps[num]->DrawPort().Height();
return height;
}
int cPixmapContainer::DrawportX(int num) {
if (checkRunning && !Running())
return 0;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return 0;
int x = pixmaps[num]->DrawPort().X();
return x;
}
int cPixmapContainer::DrawportY(int num) {
if (checkRunning && !Running())
return 0;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return 0;
int y = pixmaps[num]->DrawPort().Y();
return y;
}
void cPixmapContainer::SetDrawPortPoint(int num, const cPoint &Point) {
if (checkRunning && !Running())
return;
cMutexLock MutexLock(&mutex);
if (!pixmaps[num])
return;
pixmaps[num]->SetDrawPortPoint(Point);
}
/***************************************************************************
* HELPERS -- do not access the pixmaps array directly, use wrapper functions
* to ensure that a proper lock is set before accessing pixmaps
****************************************************************************/
void cPixmapContainer::FadeIn(void) {
if (!fadeTime)
return;
uint64_t Start = cTimeMs::Now();
int FadeFrameTime = fadeTime / 10;
while (Running()) {
uint64_t Now = cTimeMs::Now();
double t = min(double(Now - Start) / fadeTime, 1.0);
int Alpha = t * ALPHA_OPAQUE;
for (int i = 0; i < numPixmaps; i++) {
if (!PixmapExists(i))
continue;
if (pixmapsTransparency[i] > 0) {
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
SetAlpha(i, alpha);
} else {
SetAlpha(i, Alpha);
}
}
DoFlush();
int Delta = cTimeMs::Now() - Now;
if (Running() && (Delta < FadeFrameTime))
cCondWait::SleepMs(FadeFrameTime - Delta);
if ((int)(Now - Start) > fadeTime)
break;
}
}
void cPixmapContainer::FadeOut(void) {
if (!fadeTime)
return;
uint64_t Start = cTimeMs::Now();
int FadeFrameTime = fadeTime / 10;
while (true) {
uint64_t Now = cTimeMs::Now();
double t = min(double(Now - Start) / fadeTime, 1.0);
int Alpha = (1 - t) * ALPHA_OPAQUE;
for (int i = 0; i < numPixmaps; i++) {
if (!PixmapExists(i))
continue;
if (pixmapsTransparency[i] > 0) {
int alpha = (100 - pixmapsTransparency[i])*Alpha/100;
SetAlpha(i, alpha);
} else {
SetAlpha(i, Alpha);
}
}
DoFlush();
int Delta = cTimeMs::Now() - Now;
if (Running() && (Delta < FadeFrameTime))
cCondWait::SleepMs(FadeFrameTime - Delta);
if ((int)(Now - Start) > fadeTime)
break;
}
}
/*****************************************
* scrollSpeed: 1 slow
* 2 medium
* 3 fast
******************************************/
void cPixmapContainer::ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode) {
bool carriageReturn = (scrollMode == 1) ? true : false;
int scrollDelta = 1;
int drawPortX;
int FrameTime = 0;
if (scrollSpeed == 1)
FrameTime = 50;
else if (scrollSpeed == 2)
FrameTime = 30;
else
FrameTime = 15;
if (!Running())
return;
int maxX = DrawportWidth(num) - Width(num);
bool doSleep = false;
while (Running()) {
if (doSleep) {
DoSleep(scrollDelay);
doSleep = false;
}
if (!Running())
return;
uint64_t Now = cTimeMs::Now();
drawPortX = DrawportX(num);
drawPortX -= scrollDelta;
if (abs(drawPortX) > maxX) {
DoSleep(scrollDelay);
if (carriageReturn)
drawPortX = 0;
else {
scrollDelta *= -1;
drawPortX -= scrollDelta;
}
doSleep = true;
}
if (!carriageReturn && (drawPortX == 0)) {
scrollDelta *= -1;
doSleep = true;
}
SetDrawPortPoint(num, cPoint(drawPortX, 0));
int Delta = cTimeMs::Now() - Now;
DoFlush();
if (Running() && (Delta < FrameTime))
cCondWait::SleepMs(FrameTime - Delta);
}
}
/*****************************************
* scrollSpeed: 1 slow
* 2 medium
* 3 fast
******************************************/
void cPixmapContainer::ScrollVertical(int num, int scrollDelay, int scrollSpeed) {
if (!scrollSpeed)
return;
DoSleep(scrollDelay);
int drawPortY;
int FrameTime = 0;
if (scrollSpeed == 1)
FrameTime = 50;
else if (scrollSpeed == 2)
FrameTime = 30;
else
FrameTime = 15;
int maxY = DrawportHeight(num) - Height(num);
bool doSleep = false;
while (Running()) {
if (doSleep) {
doSleep = false;
DoSleep(scrollDelay);
}
uint64_t Now = cTimeMs::Now();
drawPortY = DrawportY(num);
drawPortY -= 1;
if (abs(drawPortY) > maxY) {
doSleep = true;
DoSleep(scrollDelay);
drawPortY = 0;
}
SetDrawPortPoint(num, cPoint(0, drawPortY));
if (doSleep) {
DoSleep(scrollDelay);
}
int Delta = cTimeMs::Now() - Now;
DoFlush();
if (Running() && (Delta < FrameTime))
cCondWait::SleepMs(FrameTime - Delta);
}
}
void cPixmapContainer::CancelSave(void) {
Cancel(-1);
while (Active())
cCondWait::SleepMs(10);
}
void cPixmapContainer::DoSleep(int duration) {
int sleepSlice = 10;
for (int i = 0; Running() && (i*sleepSlice < duration); i++)
cCondWait::SleepMs(sleepSlice);
}
void cPixmapContainer::DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop) {
int height = Height(num);
int numSteps = 16;
int alphaStep = 0x0F;
int alpha = 0x00;
int step, begin, end;
if (fromTop) {
step = 1;
begin = 0;
end = numSteps;
} else {
step = -1;
begin = height;
end = height - numSteps;
}
tColor clr;
bool cont = true;
for (int i = begin; cont; i = i + step) {
clr = AlphaBlend(color, colorBlending, alpha);
DrawRectangle(num, cRect(xStart,i,width,1), clr);
alpha += alphaStep;
if (i == end)
cont = false;
}
}
void cPixmapContainer::DrawRoundedCorners(int num, int radius, int x, int y, int width, int height) {
if (radius > 2) {
DrawEllipse(num, cRect(x, y, radius, radius), clrTransparent, -2);
DrawEllipse(num, cRect(x + width - radius, y , radius, radius), clrTransparent, -1);
DrawEllipse(num, cRect(x, y + height - radius, radius, radius), clrTransparent, -3);
DrawEllipse(num, cRect(x + width - radius, y + height - radius, radius, radius), clrTransparent, -4);
}
}
void cPixmapContainer::DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height) {
if (radius < 3)
return;
DrawEllipse(num, cRect(0,0,radius,radius), borderColor, -2);
DrawEllipse(num, cRect(-1,-1,radius,radius), clrTransparent, -2);
DrawEllipse(num, cRect(width-radius,0,radius,radius), borderColor, -1);
DrawEllipse(num, cRect(width-radius+1,-1,radius,radius), clrTransparent, -1);
DrawEllipse(num, cRect(0,height-radius,radius,radius), borderColor, -3);
DrawEllipse(num, cRect(-1,height-radius+1,radius,radius), clrTransparent, -3);
DrawEllipse(num, cRect(width-radius,height-radius,radius,radius), borderColor, -4);
DrawEllipse(num, cRect(width-radius+1,height-radius+1,radius,radius), clrTransparent, -4);
}

73
libcore/pixmapcontainer.h Normal file
View File

@@ -0,0 +1,73 @@
#ifndef __PIXMAP_CONTAINER_H
#define __PIXMAP_CONTAINER_H
#include <string>
#include <vdr/plugin.h>
#include "fontmanager.h"
enum eFlushState {
fsOpen,
fsLock,
fsCount,
};
class cPixmapContainer : public cThread {
private:
static cMutex mutex;
static cOsd *osd;
static eFlushState flushState;
bool pixContainerInit;
int numPixmaps;
cPixmap **pixmaps;
int *pixmapsTransparency;
bool checkRunning;
int fadeTime;
bool deleteOsdOnExit;
protected:
void SetInitFinished(void) { pixContainerInit = false; };
bool CreateOsd(int Left, int Top, int Width, int Height);
void DeleteOsdOnExit(void) { deleteOsdOnExit = true; };
void LockFlush(void);
void OpenFlush(void);
//Wrappers for access to pixmaps
bool PixmapExists(int num);
int NumPixmaps(void) { return numPixmaps; };
void CreatePixmap(int num, int Layer, const cRect &ViewPort, const cRect &DrawPort = cRect::Null);
bool DestroyPixmap(int num);
void DrawText(int num, const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, std::string fontName, int fontSize);
void DrawRectangle(int num, const cRect &Rect, tColor Color);
void DrawEllipse(int num, const cRect &Rect, tColor Color, int Quadrants = 0);
void DrawImage(int num, const cPoint &Point, const cImage &Image);
void DrawBitmap(int num, const cPoint &Point, const cBitmap &Bitmap, tColor ColorFg = 0, tColor ColorBg = 0, bool Overlay = false);
void Fill(int num, tColor Color);
void SetAlpha(int num, int Alpha);
void SetTransparency(int num, int Transparency);
void SetLayer(int num, int Layer);
int Width(int num);
int Height(int num);
int DrawportWidth(int num);
int DrawportHeight(int num);
int DrawportX(int num);
int DrawportY(int num);
void SetDrawPortPoint(int num, const cPoint &Point);
void SetCheckRunning(void) { checkRunning = true; };
void UnsetCheckRunning(void) { checkRunning = false; };
//HELPERS -- do not access the pixmaps array directly, use wrapper functions
void SetFadeTime(int fade) { fadeTime = fade; };
void FadeIn(void);
void FadeOut(void);
void ScrollVertical(int num, int scrollDelay, int scrollSpeed);
void ScrollHorizontal(int num, int scrollDelay, int scrollSpeed, int scrollMode);
void CancelSave(void);
void DoSleep(int duration);
void DrawBlendedBackground(int num, int xStart, int width, tColor color, tColor colorBlending, bool fromTop);
void DrawRoundedCorners(int num, int radius, int x, int y, int width, int height);
void DrawRoundedCornersWithBorder(int num, tColor borderColor, int radius, int width, int height);
public:
cPixmapContainer(int numPixmaps);
virtual ~cPixmapContainer(void);
void DoFlush(void);
virtual void Action(void) {};
};
#endif //__PIXMAP_CONTAINER_H

84
libcore/timers.c Normal file
View File

@@ -0,0 +1,84 @@
#include "timers.h"
#include "../services/epgsearch.h"
#include "../services/remotetimers.h"
static int CompareTimers(const void *a, const void *b) {
return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
}
cGlobalSortedTimers::cGlobalSortedTimers(bool forceRefresh) : cVector<const cTimer *>(Timers.Count()) {
static bool initial = true;
static cRemoteTimerRefresh *remoteTimerRefresh = NULL;
if (forceRefresh)
initial = true;
//check if remotetimers plugin is available
static cPlugin* pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
cSchedulesLock SchedulesLock;
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
if (pRemoteTimers && initial) {
cString errorMsg;
pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg);
initial = false;
}
for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer))
Append(Timer);
//if remotetimers plugin is available, take timers also from him
if (pRemoteTimers) {
cTimer* remoteTimer = NULL;
while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) {
remoteTimer->SetEventFromSchedule(Schedules); // make sure the event is current
Append(remoteTimer);
}
}
Sort(CompareTimers);
if (pRemoteTimers && (remoteTimerRefresh == NULL))
remoteTimerRefresh = new cRemoteTimerRefresh();
}
int cGlobalSortedTimers::NumTimerConfilicts(void) {
int numConflicts = 0;
cPlugin *p = cPluginManager::GetPlugin("epgsearch");
if (p) {
Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0;
if (serviceData) {
serviceData->nextConflict = 0;
serviceData->relevantConflicts = 0;
serviceData->totalConflicts = 0;
p->Service("Epgsearch-lastconflictinfo-v1.0", serviceData);
if (serviceData->relevantConflicts > 0) {
numConflicts = serviceData->relevantConflicts;
}
delete serviceData;
}
}
return numConflicts;
}
cRemoteTimerRefresh::cRemoteTimerRefresh(): cThread("skindesigner: RemoteTimers::RefreshTimers") {
Start();
}
cRemoteTimerRefresh::~cRemoteTimerRefresh(void) {
Cancel(-1);
while (Active())
cCondWait::SleepMs(10);
}
void cRemoteTimerRefresh::Action(void) {
#define REFESH_INTERVALL_MS 30000
while (Running()) {
cCondWait::SleepMs(REFESH_INTERVALL_MS);
if (!cOsd::IsOpen()) {//make sure that no timer is currently being edited
cGlobalSortedTimers(true);
Timers.SetModified();
}
}
}

20
libcore/timers.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef __NOPACITY_TIMERS_H
#define __NOPACITY_TIMERS_H
#include <vdr/timers.h>
#include <vdr/plugin.h>
class cGlobalSortedTimers : public cVector<const cTimer *> {
public:
cGlobalSortedTimers(bool forceRefresh = false);
int NumTimerConfilicts(void);
};
class cRemoteTimerRefresh: public cThread {
protected:
virtual void Action(void);
public:
cRemoteTimerRefresh(void);
virtual ~cRemoteTimerRefresh(void);
};
#endif //__NOPACITY_TIMERS_H