mirror of
https://projects.vdr-developer.org/git/vdr-plugin-skindesigner.git
synced 2023-10-19 17:58:31 +02:00
1131 lines
38 KiB
C
1131 lines
38 KiB
C
#include "view.h"
|
|
#include "../config.h"
|
|
#include "../libcore/helpers.h"
|
|
#include "../libcore/imageloader.h"
|
|
|
|
using namespace std;
|
|
|
|
cView::cView(cTemplateView *tmplView) : cPixmapContainer(tmplView->GetNumPixmaps()) {
|
|
this->tmplView = tmplView;
|
|
tvScaled = tmplView->GetScalingWindow(scalingWindow);
|
|
if (tvScaled) {
|
|
cDevice::PrimaryDevice()->ScaleVideo(scalingWindow);
|
|
}
|
|
tmplViewElement = NULL;
|
|
tmplTab = NULL;
|
|
Init();
|
|
}
|
|
|
|
cView::cView(cTemplateViewElement *tmplViewElement) : cPixmapContainer(tmplViewElement ? tmplViewElement->GetNumPixmaps() : 0) {
|
|
this->tmplViewElement = tmplViewElement;
|
|
tmplView = NULL;
|
|
tmplTab = NULL;
|
|
tvScaled = false;
|
|
Init();
|
|
}
|
|
|
|
cView::cView(cTemplateViewTab *tmplTab) : cPixmapContainer(1) {
|
|
this->tmplTab = tmplTab;
|
|
tmplView = NULL;
|
|
tmplViewElement = NULL;
|
|
tvScaled = false;
|
|
Init();
|
|
}
|
|
|
|
cView::~cView() {
|
|
if (tvScaled) {
|
|
cDevice::PrimaryDevice()->ScaleVideo(cRect::Null);
|
|
}
|
|
for (map<eViewElement,cViewElement*>::iterator dVeIt = detachedViewElements.begin(); dVeIt != detachedViewElements.end(); dVeIt++) {
|
|
cViewElement *ve = dVeIt->second;
|
|
delete ve;
|
|
}
|
|
}
|
|
|
|
void cView::Init(void) {
|
|
viewInit = true;
|
|
scrolling = false;
|
|
veScroll = veUndefined;
|
|
scrollingPix = -1;
|
|
scrollOrientation = orHorizontal;
|
|
scrollDelay = 0;
|
|
scrollMode = smNone;
|
|
scrollSpeed = ssMedium;
|
|
currentlyScrolling = false;
|
|
}
|
|
|
|
void cView::Action(void) {
|
|
if (scrolling) {
|
|
DoSleep(scrollDelay);
|
|
if (scrollOrientation == orHorizontal) {
|
|
ActivateScrolling();
|
|
ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
|
|
} else {
|
|
ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
|
|
}
|
|
}
|
|
}
|
|
|
|
void cView::Stop(void) {
|
|
CancelSave();
|
|
}
|
|
|
|
/********************************************************************************
|
|
* Protected Functions
|
|
********************************************************************************/
|
|
|
|
void cView::DrawViewElement(eViewElement ve, map <string,string> *stringTokens, map <string,int> *intTokens, map < string, vector< map< string, string > > > *loopTokens) {
|
|
//setting correct ViewElement, depending which constructor was used
|
|
cTemplateViewElement *viewElement = NULL;
|
|
if (tmplViewElement) {
|
|
viewElement = tmplViewElement;
|
|
} else if (tmplView) {
|
|
viewElement = tmplView->GetViewElement(ve);
|
|
}
|
|
if (!viewElement)
|
|
return;
|
|
|
|
if (viewElement->DebugTokens()) {
|
|
DebugTokens(tmplView ? (tmplView->GetViewElementName(ve)) : "current view", stringTokens, intTokens, loopTokens);
|
|
}
|
|
//iterate through pixmaps of viewelement
|
|
int pixCurrent = viewElement->GetPixOffset();
|
|
if (pixCurrent < 0)
|
|
return;
|
|
viewElement->InitIterator();
|
|
cTemplatePixmap *pix = NULL;
|
|
while(pix = viewElement->GetNextPixmap()) {
|
|
//check if already drawn background area, this can be skipped
|
|
if (PixmapExists(pixCurrent) && pix->BackgroundArea()) {
|
|
pixCurrent++;
|
|
continue;
|
|
}
|
|
//reset Template
|
|
pix->ClearDynamicParameters();
|
|
//create Pixmap if already fully parsed
|
|
if (!PixmapExists(pixCurrent) && pix->Ready() && pix->DoExecute() && !pix->Scrolling()) {
|
|
CreateViewPixmap(pixCurrent, pix);
|
|
}
|
|
//check if pixmap needs dynamic parameters
|
|
if ((!pix->Ready() || !pix->DoExecute()) && !pix->Scrolling()) {
|
|
//parse dynamic parameters and initiate functions
|
|
pix->ParseDynamicParameters(intTokens, true);
|
|
if (pix->Ready() && pix->DoExecute()) {
|
|
CreateViewPixmap(pixCurrent, pix);
|
|
}
|
|
} else {
|
|
//parse dynamic parameters but not initiate functions
|
|
pix->ParseDynamicParameters(intTokens, false);
|
|
}
|
|
//if pixmap still not valid, skip
|
|
if (!pix->Ready() && !pix->Scrolling()) {
|
|
pixCurrent++;
|
|
continue;
|
|
}
|
|
//if condition for pixmap set, check if cond is true
|
|
if (!pix->DoExecute()) {
|
|
pixCurrent++;
|
|
continue;
|
|
}
|
|
//parse dynamic tokens of pixmap functions
|
|
pix->ClearDynamicFunctionParameters();
|
|
pix->ParseDynamicFunctionParameters(stringTokens, intTokens);
|
|
|
|
if (!PixmapExists(pixCurrent) && pix->Scrolling()) {
|
|
cSize drawportSize;
|
|
scrolling = pix->CalculateDrawPortSize(drawportSize, loopTokens);
|
|
if (scrolling) {
|
|
CreateScrollingPixmap(pixCurrent, pix, drawportSize);
|
|
pix->SetScrollingTextWidth();
|
|
veScroll = ve;
|
|
scrollingPix = pixCurrent;
|
|
scrollOrientation = pix->GetNumericParameter(ptOrientation);
|
|
scrollMode = pix->GetNumericParameter(ptScrollMode);
|
|
scrollDelay = pix->GetNumericParameter(ptDelay);
|
|
scrollSpeed = pix->GetNumericParameter(ptScrollSpeed);
|
|
} else {
|
|
CreateViewPixmap(pixCurrent, pix);
|
|
}
|
|
}
|
|
if (pix->DoDebug()) {
|
|
pix->Debug();
|
|
}
|
|
|
|
DrawPixmap(pixCurrent, pix, loopTokens);
|
|
pixCurrent++;
|
|
}
|
|
}
|
|
|
|
void cView::ClearViewElement(eViewElement ve) {
|
|
cTemplateViewElement *viewElement = NULL;
|
|
if (tmplViewElement) {
|
|
viewElement = tmplViewElement;
|
|
} else if (tmplView) {
|
|
viewElement = tmplView->GetViewElement(ve);
|
|
}
|
|
if (!viewElement)
|
|
return;
|
|
int pixCurrent = viewElement->GetPixOffset();
|
|
if (pixCurrent < 0)
|
|
return;
|
|
cTemplatePixmap *pix = NULL;
|
|
viewElement->InitIterator();
|
|
while(pix = viewElement->GetNextPixmap()) {
|
|
if (!pix->BackgroundArea()) {
|
|
Fill(pixCurrent, clrTransparent);
|
|
}
|
|
pixCurrent++;
|
|
}
|
|
}
|
|
|
|
void cView::DestroyViewElement(eViewElement ve) {
|
|
if (!tmplView)
|
|
return;
|
|
cTemplateViewElement *viewElement = tmplView->GetViewElement(ve);
|
|
if (!viewElement)
|
|
return;
|
|
int pixCurrent = viewElement->GetPixOffset();
|
|
if (pixCurrent < 0)
|
|
return;
|
|
cTemplatePixmap *pix = NULL;
|
|
viewElement->InitIterator();
|
|
while(pix = viewElement->GetNextPixmap()) {
|
|
DestroyPixmap(pixCurrent);
|
|
pixCurrent++;
|
|
}
|
|
}
|
|
|
|
void cView::ActivateScrolling(void) {
|
|
if (veScroll == veUndefined)
|
|
return;
|
|
cTemplateViewElement *scrollViewElement = NULL;
|
|
if (tmplView) {
|
|
scrollViewElement = tmplView->GetViewElement(veScroll);
|
|
}
|
|
if (!scrollViewElement)
|
|
return;
|
|
|
|
ClearViewElement(veScroll);
|
|
currentlyScrolling = true;
|
|
|
|
int pixCurrent = scrollViewElement->GetPixOffset();
|
|
if (pixCurrent < 0)
|
|
return;
|
|
scrollViewElement->InitIterator();
|
|
cTemplatePixmap *pix = NULL;
|
|
while(pix = scrollViewElement->GetNextPixmap()) {
|
|
DrawPixmap(pixCurrent, pix);
|
|
pixCurrent++;
|
|
}
|
|
}
|
|
|
|
bool cView::ExecuteViewElement(eViewElement ve) {
|
|
if (!tmplView)
|
|
return false;
|
|
bool doExecute = tmplView->ExecuteView(ve);
|
|
if (!doExecute)
|
|
return false;
|
|
return tmplView->GetNumPixmapsViewElement(ve);
|
|
}
|
|
|
|
bool cView::DetachViewElement(eViewElement ve) {
|
|
if (!tmplView)
|
|
return false;
|
|
return tmplView->DetachViewElement(ve);
|
|
}
|
|
|
|
bool cView::ViewElementScrolls(eViewElement ve) {
|
|
if (scrollingPix < 0)
|
|
return false;
|
|
if (!tmplView)
|
|
return false;
|
|
cTemplateViewElement *viewElement = tmplView->GetViewElement(ve);
|
|
if (!viewElement)
|
|
return false;
|
|
int pixStart = viewElement->GetPixOffset();
|
|
int numPixmaps = viewElement->GetNumPixmaps();
|
|
if ( (scrollingPix >= pixStart) && (scrollingPix < (pixStart + numPixmaps)) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
cViewElement *cView::GetViewElement(eViewElement ve) {
|
|
map < eViewElement, cViewElement* >::iterator hit = detachedViewElements.find(ve);
|
|
if (hit == detachedViewElements.end())
|
|
return NULL;
|
|
cViewElement *viewElement = hit->second;
|
|
return viewElement;
|
|
}
|
|
|
|
void cView::AddViewElement(eViewElement ve, cViewElement *viewElement) {
|
|
detachedViewElements.insert(pair< eViewElement, cViewElement* >(ve, viewElement));
|
|
}
|
|
|
|
void cView::CreateViewPixmap(int num, cTemplatePixmap *pix, cRect *size) {
|
|
cRect pixSize;
|
|
if (size) {
|
|
pixSize = *size;
|
|
} else {
|
|
pixSize = pix->GetPixmapSize();
|
|
}
|
|
int layer = pix->GetNumericParameter(ptLayer);
|
|
int transparency = pix->GetNumericParameter(ptTransparency);
|
|
SetTransparency(num, transparency);
|
|
CreatePixmap(num, layer, pixSize);
|
|
}
|
|
|
|
void cView::CreateScrollingPixmap(int num, cTemplatePixmap *pix, cSize &drawportSize) {
|
|
cRect pixViewPort = pix->GetPixmapSize();
|
|
cRect drawPort;
|
|
drawPort.SetX(0);
|
|
drawPort.SetY(0);
|
|
drawPort.SetWidth(drawportSize.Width());
|
|
drawPort.SetHeight(drawportSize.Height());
|
|
int layer = pix->GetNumericParameter(ptLayer);
|
|
int transparency = pix->GetNumericParameter(ptTransparency);
|
|
SetTransparency(num, transparency);
|
|
CreatePixmap(num, layer, pixViewPort, drawPort);
|
|
}
|
|
|
|
void cView::DrawPixmap(int num, cTemplatePixmap *pix, map < string, vector< map< string, string > > > *loopTokens, bool flushPerLoop) {
|
|
pix->InitIterator();
|
|
cTemplateFunction *func = NULL;
|
|
while(func = pix->GetNextFunction()) {
|
|
eFuncType type = func->GetType();
|
|
if (func->DoDebug()) {
|
|
func->Debug();
|
|
}
|
|
if (!func->DoExecute()) {
|
|
continue;
|
|
}
|
|
switch (type) {
|
|
case ftFill:
|
|
DoFill(num, func);
|
|
break;
|
|
case ftDrawText:
|
|
DoDrawText(num, func);
|
|
break;
|
|
case ftDrawTextVertical:
|
|
DoDrawTextVertical(num, func);
|
|
break;
|
|
case ftDrawTextBox: {
|
|
int floating = func->GetNumericParameter(ptFloat);
|
|
if (floating > flNone) {
|
|
DoDrawFloatingTextBox(num, func);
|
|
} else {
|
|
DoDrawTextBox(num, func);
|
|
}
|
|
break; }
|
|
case ftDrawRectangle:
|
|
DoDrawRectangle(num, func);
|
|
break;
|
|
case ftDrawEllipse:
|
|
DoDrawEllipse(num, func);
|
|
break;
|
|
case ftDrawSlope:
|
|
DoDrawSlope(num, func);
|
|
break;
|
|
case ftDrawImage:
|
|
DoDrawImage(num, func);
|
|
break;
|
|
case ftLoop:
|
|
if (loopTokens)
|
|
DrawLoop(num, func, loopTokens);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (flushPerLoop) {
|
|
DoFlush();
|
|
}
|
|
}
|
|
}
|
|
|
|
void cView::DrawLoop(int numPixmap, cTemplateFunction *func, map < string, vector< map< string, string > > > *loopTokens) {
|
|
cTemplateLoopFunction *loopFunc = dynamic_cast<cTemplateLoopFunction*>(func);
|
|
if (!loopFunc)
|
|
return;
|
|
|
|
int loopX0 = loopFunc->GetNumericParameter(ptX);
|
|
if (loopX0 < 0) loopX0 = 0;
|
|
int loopY0 = loopFunc->GetNumericParameter(ptY);
|
|
if (loopY0 < 0) loopY0 = 0;
|
|
int orientation = loopFunc->GetNumericParameter(ptOrientation);
|
|
int loopWidth = loopFunc->GetNumericParameter(ptWidth);
|
|
if (loopWidth <= 0)
|
|
loopWidth = loopFunc->GetContainerWidth();
|
|
int loopHeight = loopFunc->GetNumericParameter(ptHeight);
|
|
if (loopHeight <= 0)
|
|
loopHeight = loopFunc->GetContainerHeight();
|
|
int columnWidth = loopFunc->GetNumericParameter(ptColumnWidth);
|
|
int rowHeight = loopFunc->GetNumericParameter(ptRowHeight);
|
|
int overflow = loopFunc->GetNumericParameter(ptOverflow);
|
|
|
|
int x0 = loopX0;
|
|
int y0 = loopY0;
|
|
|
|
string loopTokenName = loopFunc->GetParameter(ptName);
|
|
|
|
map < string, vector< map< string, string > > >::iterator hit = loopTokens->find(loopTokenName);
|
|
if (hit == loopTokens->end())
|
|
return;
|
|
vector< map<string,string> > loopToken = hit->second;
|
|
int lineNumber=0;
|
|
for (vector< map<string,string> >::iterator line = loopToken.begin(); line != loopToken.end(); line++) {
|
|
//check overflow behaviour
|
|
if (overflow == otCut) {
|
|
if (orientation == orHorizontal) {
|
|
if (lineNumber * columnWidth > loopWidth) {
|
|
return;
|
|
}
|
|
} else if (orientation == orVertical) {
|
|
if (lineNumber * rowHeight > loopHeight) {
|
|
return;
|
|
}
|
|
}
|
|
} else if (overflow == otWrap && orientation == orHorizontal) {
|
|
if (x0 + columnWidth > loopWidth) {
|
|
x0 = loopX0;
|
|
if (rowHeight > 0) {
|
|
y0 += rowHeight;
|
|
} else {
|
|
y0 += loopFunc->GetLoopElementsHeight();
|
|
}
|
|
}
|
|
}
|
|
map<string,string> tokens = *line;
|
|
loopFunc->ClearDynamicParameters();
|
|
loopFunc->ParseDynamicParameters(&tokens);
|
|
loopFunc->InitIterator();
|
|
cTemplateFunction *func = NULL;
|
|
while(func = loopFunc->GetNextFunction()) {
|
|
//do debug?
|
|
if (func->DoDebug())
|
|
func->Debug();
|
|
//check if set condition is true
|
|
if (!func->DoExecute()) {
|
|
continue;
|
|
}
|
|
//execute
|
|
eFuncType type = func->GetType();
|
|
switch (type) {
|
|
case ftDrawText:
|
|
DoDrawText(numPixmap, func, x0, y0);
|
|
break;
|
|
case ftDrawTextBox:
|
|
DoDrawTextBox(numPixmap, func, x0, y0);
|
|
break;
|
|
case ftDrawRectangle:
|
|
DoDrawRectangle(numPixmap, func, x0, y0);
|
|
break;
|
|
case ftDrawEllipse:
|
|
DoDrawEllipse(numPixmap, func, x0, y0);
|
|
break;
|
|
case ftDrawSlope:
|
|
DoDrawSlope(numPixmap, func, x0, y0);
|
|
break;
|
|
case ftDrawImage:
|
|
DoDrawImage(numPixmap, func, x0, y0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
//calculate position of next loop element
|
|
if (orientation == orHorizontal) {
|
|
if (columnWidth > 0) {
|
|
x0 += columnWidth;
|
|
} else {
|
|
x0 += loopFunc->GetLoopElementsWidth();
|
|
}
|
|
} else if (orientation == orVertical) {
|
|
if (rowHeight > 0) {
|
|
y0 += rowHeight;
|
|
} else {
|
|
y0 += loopFunc->GetLoopElementsHeight();
|
|
}
|
|
}
|
|
lineNumber++;
|
|
//DoFlush();
|
|
}
|
|
}
|
|
|
|
void cView::DebugTokens(string viewElement, map<string,string> *stringTokens, map<string,int> *intTokens, map < string, vector< map< string, string > > > *loopTokens) {
|
|
esyslog("skindesigner: ------------------------------ Tokens for %s:", viewElement.c_str());
|
|
if (stringTokens) {
|
|
for (map<string,string>::iterator st = stringTokens->begin(); st != stringTokens->end(); st++) {
|
|
esyslog("skindesigner: string var \"%s\" = \"%s\"", (st->first).c_str(), (st->second).c_str());
|
|
}
|
|
}
|
|
if (intTokens) {
|
|
for (map<string,int>::iterator it = intTokens->begin(); it != intTokens->end(); it++) {
|
|
esyslog("skindesigner: int var \"%s\" = %d", (it->first).c_str(), it->second);
|
|
}
|
|
}
|
|
if (loopTokens) {
|
|
for(map < string, vector< map< string, string > > >::iterator it1 = loopTokens->begin(); it1 != loopTokens->end(); it1++) {
|
|
int line = 0;
|
|
string tokenName = it1->first;
|
|
vector< map<string,string> > tokens = it1->second;
|
|
esyslog("skindesigner: loop token %s", tokenName.c_str());
|
|
for (vector< map<string,string> >::iterator it2 = tokens.begin(); it2 != tokens.end(); it2++) {
|
|
esyslog("skindesigner: loop tokens line %d:", line++);
|
|
map<string,string> element = *it2;
|
|
for (map<string,string>::iterator el = element.begin(); el != element.end(); el++) {
|
|
esyslog("skindesigner: name: %s, value: %s", (el->first).c_str(), (el->second).c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Private Functions
|
|
*****************************************************************/
|
|
|
|
void cView::DoFill(int num, cTemplateFunction *func) {
|
|
tColor col = func->GetColorParameter(ptColor);
|
|
Fill(num, col);
|
|
}
|
|
|
|
void cView::DoDrawText(int num, cTemplateFunction *func, int x0, int y0) {
|
|
int x = func->GetNumericParameter(ptX);
|
|
if (x < 0) x = 0;
|
|
x += x0;
|
|
int y = func->GetNumericParameter(ptY);
|
|
if (y < 0) y = 0;
|
|
y += y0;
|
|
cPoint pos(x,y);
|
|
string fontName = func->GetFontName();
|
|
int fontSize = func->GetNumericParameter(ptFontSize);
|
|
tColor clr = func->GetColorParameter(ptColor);
|
|
tColor clrBack = clrTransparent;
|
|
string text = "";
|
|
if (!currentlyScrolling) {
|
|
text = func->GetText(true);
|
|
} else {
|
|
text = func->GetText(false);
|
|
}
|
|
DrawText(num, pos, text.c_str(), clr, clrBack, fontName, fontSize);
|
|
}
|
|
|
|
void cView::DoDrawTextVertical(int num, cTemplateFunction *func, int x0, int y0) {
|
|
string fontName = func->GetFontName();
|
|
int fontSize = func->GetNumericParameter(ptFontSize);
|
|
int direction = func->GetNumericParameter(ptDirection);
|
|
tColor clr = func->GetColorParameter(ptColor);
|
|
string text = func->GetText(false);
|
|
cImage *textVertical = imgCache->GetVerticalText(text, clr, fontName, fontSize, direction);
|
|
if (!textVertical)
|
|
return;
|
|
|
|
//align has to be set here because here we know the image size
|
|
int x = 0;
|
|
int y = 0;
|
|
int align = func->GetNumericParameter(ptAlign);
|
|
if (align == alCenter) {
|
|
int containerWidth = func->GetContainerWidth();
|
|
x = (containerWidth - textVertical->Width()) / 2;
|
|
} else if (align == alLeft) {
|
|
x = 0;
|
|
} else if (align == alRight) {
|
|
int containerWidth = func->GetContainerWidth();
|
|
x = (containerWidth - textVertical->Width());
|
|
} else {
|
|
x = func->GetNumericParameter(ptX);
|
|
}
|
|
|
|
int valign = func->GetNumericParameter(ptValign);
|
|
if (valign == alCenter) {
|
|
int containerHeight = func->GetContainerHeight();
|
|
y = (containerHeight - textVertical->Height()) / 2;
|
|
} else if (align == alTop) {
|
|
y = 0;
|
|
} else if (align == alBottom) {
|
|
int containerHeight = func->GetContainerHeight();
|
|
y = (containerHeight - textVertical->Height());
|
|
} else {
|
|
y = func->GetNumericParameter(ptY);
|
|
}
|
|
if (x < 0) x = 0;
|
|
x += x0;
|
|
if (y < 0) y = func->GetContainerHeight() - textVertical->Height() - 5;
|
|
y += y0;
|
|
cPoint pos(x,y);
|
|
DrawImage(num, pos, *textVertical);
|
|
}
|
|
|
|
void cView::DoDrawTextBox(int num, cTemplateFunction *func, int x0, int y0) {
|
|
string text = func->GetText(false);
|
|
if (text.size() < 3)
|
|
return;
|
|
int x = func->GetNumericParameter(ptX);
|
|
int y = func->GetNumericParameter(ptY);
|
|
if (x < 0) x = 0;
|
|
x += x0;
|
|
if (y < 0) y = 0;
|
|
y += y0;
|
|
int width = func->GetNumericParameter(ptWidth);
|
|
int height = func->GetNumericParameter(ptHeight);
|
|
string fontName = func->GetFontName();
|
|
int fontSize = func->GetNumericParameter(ptFontSize);
|
|
int align = func->GetNumericParameter(ptAlign);
|
|
int maxLines = func->GetNumericParameter(ptMaxLines);
|
|
tColor clr = func->GetColorParameter(ptColor);
|
|
tColor clrBack = clrTransparent;
|
|
const cFont *font = fontManager->Font(fontName, fontSize);
|
|
if (!font)
|
|
return;
|
|
cTextWrapper wrapper;
|
|
wrapper.Set(text.c_str(), font, width);
|
|
int fontHeight = fontManager->Height(fontName, fontSize);
|
|
int lines = wrapper.Lines();
|
|
int yLine = y;
|
|
for (int line=0; line < lines; line++) {
|
|
int xLine = x;
|
|
if (align == alCenter) {
|
|
int textWidth = font->Width(wrapper.GetLine(line));
|
|
xLine += (width - textWidth)/2;
|
|
} else if (align == alRight) {
|
|
int textWidth = font->Width(wrapper.GetLine(line));
|
|
xLine += (width - textWidth);
|
|
}
|
|
cPoint pos(xLine, yLine);
|
|
if (maxLines > 0 && line == maxLines-1) {
|
|
string lastLine = wrapper.GetLine(line);
|
|
if (lines > maxLines) {
|
|
lastLine += "...";
|
|
}
|
|
DrawText(num, pos, lastLine.c_str(), clr, clrBack, fontName, fontSize);
|
|
break;
|
|
} else if (height > 0 && yLine - y + 2*fontHeight > height) {
|
|
DrawText(num, pos, "...", clr, clrBack, fontName, fontSize);
|
|
break;
|
|
}
|
|
DrawText(num, pos, wrapper.GetLine(line), clr, clrBack, fontName, fontSize);
|
|
yLine += fontHeight;
|
|
}
|
|
}
|
|
|
|
void cView::DoDrawFloatingTextBox(int num, cTemplateFunction *func) {
|
|
string text = func->GetText(false);
|
|
if (text.size() < 3)
|
|
return;
|
|
int x = func->GetNumericParameter(ptX);
|
|
int y = func->GetNumericParameter(ptY);
|
|
if (x < 0) x = 0;
|
|
if (y < 0) y = 0;
|
|
int width = func->GetNumericParameter(ptWidth);
|
|
int height = func->GetNumericParameter(ptHeight);
|
|
string fontName = func->GetFontName();
|
|
int fontSize = func->GetNumericParameter(ptFontSize);
|
|
tColor clr = func->GetColorParameter(ptColor);
|
|
tColor clrBack = clrTransparent;
|
|
const cFont *font = fontManager->Font(fontName, fontSize);
|
|
if (!font)
|
|
return;
|
|
int floatType = func->GetNumericParameter(ptFloat);
|
|
int floatWidth = func->GetNumericParameter(ptFloatWidth);
|
|
int floatHeight = func->GetNumericParameter(ptFloatHeight);
|
|
|
|
cTextWrapper wTextTall;
|
|
cTextWrapper wTextFull;
|
|
|
|
int fontHeight = fontManager->Height(fontName, fontSize);
|
|
int linesNarrow = floatHeight / fontHeight;
|
|
int widthNarrow = width - floatWidth;
|
|
int linesDrawn = 0;
|
|
int curY = 0;
|
|
bool drawNarrow = true;
|
|
|
|
splitstring s(text.c_str());
|
|
std::vector<std::string> flds = s.split('\n', 1);
|
|
|
|
if (flds.size() < 1)
|
|
return;
|
|
|
|
std::stringstream sstrTextTall;
|
|
std::stringstream sstrTextFull;
|
|
|
|
for (int i=0; i < (int)flds.size(); i++) {
|
|
if (!flds[i].size()) {
|
|
//empty line
|
|
linesDrawn++;
|
|
curY += fontHeight;
|
|
if (drawNarrow)
|
|
sstrTextTall << "\n";
|
|
else
|
|
sstrTextFull << "\n";
|
|
} else {
|
|
cTextWrapper wrapper;
|
|
if (drawNarrow) {
|
|
wrapper.Set((flds[i].c_str()), font, widthNarrow);
|
|
int newLines = wrapper.Lines();
|
|
//check if wrapper fits completely into narrow area
|
|
if (linesDrawn + newLines < linesNarrow) {
|
|
for (int line = 0; line < wrapper.Lines(); line++) {
|
|
sstrTextTall << wrapper.GetLine(line) << " ";
|
|
}
|
|
sstrTextTall << "\n";
|
|
linesDrawn += newLines;
|
|
} else {
|
|
//this wrapper has to be splitted
|
|
for (int line = 0; line < wrapper.Lines(); line++) {
|
|
if (line + linesDrawn < linesNarrow) {
|
|
sstrTextTall << wrapper.GetLine(line) << " ";
|
|
} else {
|
|
sstrTextFull << wrapper.GetLine(line) << " ";
|
|
}
|
|
}
|
|
sstrTextFull << "\n";
|
|
drawNarrow = false;
|
|
}
|
|
} else {
|
|
wrapper.Set((flds[i].c_str()), font, width);
|
|
for (int line = 0; line < wrapper.Lines(); line++) {
|
|
sstrTextFull << wrapper.GetLine(line) << " ";
|
|
}
|
|
sstrTextFull << "\n";
|
|
}
|
|
}
|
|
}
|
|
//VDRs textwrapper swallows linebreaks at the end, so we have to fix that manually
|
|
string textTall = sstrTextTall.str();
|
|
size_t posLastCarriageReturn = textTall.find_last_not_of("\n");
|
|
|
|
int numLinesToAddAtTall = 0;
|
|
if (posLastCarriageReturn != string::npos && (posLastCarriageReturn < textTall.size() - 1)) {
|
|
numLinesToAddAtTall = textTall.size() - posLastCarriageReturn - 2;
|
|
}
|
|
|
|
wTextTall.Set(textTall.c_str(), font, widthNarrow);
|
|
wTextFull.Set(sstrTextFull.str().c_str(), font, width);
|
|
|
|
int textLinesTall = wTextTall.Lines();
|
|
int textLinesFull = wTextFull.Lines();
|
|
|
|
int textXTall = x;
|
|
if (floatType == flTopLeft)
|
|
textXTall = x + floatWidth;
|
|
|
|
int yLine = y;
|
|
for (int line=0; line < textLinesTall; line++) {
|
|
cPoint pos(textXTall, yLine);
|
|
DrawText(num, pos, wTextTall.GetLine(line), clr, clrBack, fontName, fontSize);
|
|
yLine += fontHeight;
|
|
}
|
|
|
|
if (numLinesToAddAtTall) {
|
|
yLine += numLinesToAddAtTall * fontHeight;
|
|
}
|
|
|
|
for (int line=0; line < textLinesFull; line++) {
|
|
cPoint pos(x, yLine);
|
|
if (height > 0 && yLine - y + 2*fontHeight > height) {
|
|
DrawText(num, pos, "...", clr, clrBack, fontName, fontSize);
|
|
break;
|
|
}
|
|
DrawText(num, pos, wTextFull.GetLine(line), clr, clrBack, fontName, fontSize);
|
|
yLine += fontHeight;
|
|
}
|
|
}
|
|
|
|
void cView::DoDrawRectangle(int num, cTemplateFunction *func, int x0, int y0) {
|
|
int x = func->GetNumericParameter(ptX);
|
|
int y = func->GetNumericParameter(ptY);
|
|
if (x < 0) x = 0;
|
|
x += x0;
|
|
if (y < 0) y = 0;
|
|
y += y0;
|
|
int w = func->GetNumericParameter(ptWidth);
|
|
int h = func->GetNumericParameter(ptHeight);
|
|
cRect size(x, y, w, h);
|
|
tColor clr = func->GetColorParameter(ptColor);
|
|
DrawRectangle(num, size, clr);
|
|
}
|
|
|
|
void cView::DoDrawEllipse(int num, cTemplateFunction *func, int x0, int y0) {
|
|
int x = func->GetNumericParameter(ptX);
|
|
int y = func->GetNumericParameter(ptY);
|
|
if (x < 0) x = 0;
|
|
x += x0;
|
|
if (y < 0) y = 0;
|
|
y += y0;
|
|
int w = func->GetNumericParameter(ptWidth);
|
|
int h = func->GetNumericParameter(ptHeight);
|
|
cRect size(x, y, w, h);
|
|
tColor clr = func->GetColorParameter(ptColor);
|
|
int quadrant = func->GetNumericParameter(ptQuadrant);
|
|
if (quadrant < -4 || quadrant > 8) {
|
|
esyslog("skindesigner: wrong quadrant %d for drawellipse, allowed values are from -4 to 8", quadrant);
|
|
quadrant = 0;
|
|
}
|
|
DrawEllipse(num, size, clr, quadrant);
|
|
}
|
|
|
|
void cView::DoDrawSlope(int num, cTemplateFunction *func, int x0, int y0) {
|
|
int x = func->GetNumericParameter(ptX);
|
|
int y = func->GetNumericParameter(ptY);
|
|
if (x < 0) x = 0;
|
|
x += x0;
|
|
if (y < 0) y = 0;
|
|
y += y0;
|
|
int w = func->GetNumericParameter(ptWidth);
|
|
int h = func->GetNumericParameter(ptHeight);
|
|
cRect size(x, y, w, h);
|
|
tColor clr = func->GetColorParameter(ptColor);
|
|
int type = func->GetNumericParameter(ptType);
|
|
if (type < 0 || type > 7) {
|
|
esyslog("skindesigner: wrong type %d for drawslope, allowed values are from 0 to 7", type);
|
|
type = 0;
|
|
}
|
|
DrawSlope(num, size, clr, type);
|
|
}
|
|
|
|
void cView::DoDrawImage(int num, cTemplateFunction *func, int x0, int y0) {
|
|
int x = func->GetNumericParameter(ptX);
|
|
int y = func->GetNumericParameter(ptY);
|
|
if (x < 0) x = 0;
|
|
x += x0;
|
|
if (y < 0) y = 0;
|
|
y += y0;
|
|
cPoint pos(x,y);
|
|
int width = func->GetNumericParameter(ptWidth);
|
|
int height = func->GetNumericParameter(ptHeight);
|
|
string path = func->GetImagePath();
|
|
eImageType type = (eImageType)func->GetNumericParameter(ptImageType);
|
|
switch (type) {
|
|
case itChannelLogo: {
|
|
cImage *logo = imgCache->GetLogo(path, width, height);
|
|
if (logo) {
|
|
DrawImage(num, pos, *logo);
|
|
}
|
|
break; }
|
|
case itSepLogo: {
|
|
cImage *sepLogo = imgCache->GetSeparatorLogo(path, width, height);
|
|
if (sepLogo) {
|
|
DrawImage(num, pos, *sepLogo);
|
|
}
|
|
break; }
|
|
case itSkinPart: {
|
|
cImage *skinpart = imgCache->GetSkinpart(path, width, height);
|
|
if (skinpart) {
|
|
DrawImage(num, pos, *skinpart);
|
|
}
|
|
break; }
|
|
case itIcon: {
|
|
cImage *icon = imgCache->GetIcon(type, path, width, height);
|
|
if (icon) {
|
|
DrawImage(num, pos, *icon);
|
|
}
|
|
break; }
|
|
case itMenuIcon: {
|
|
cImage *icon = imgCache->GetIcon(type, path, width, height);
|
|
if (icon) {
|
|
DrawImage(num, pos, *icon);
|
|
}
|
|
break; }
|
|
case itImage: {
|
|
cImageLoader imgLoader;
|
|
if (imgLoader.LoadImage(path.c_str())) {
|
|
cImage *image = imgLoader.CreateImage(width, height);
|
|
DrawImage(num, pos, *image);
|
|
delete(image);
|
|
}
|
|
break; }
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
* cViewElement
|
|
************************************************************************/
|
|
|
|
cViewElement::cViewElement(cTemplateViewElement *tmplViewElement) : cView(tmplViewElement) {
|
|
tmplViewElement->SetPixOffset(0);
|
|
delay = tmplViewElement->GetNumericParameter(ptDelay);
|
|
SetFadeTime(tmplViewElement->GetNumericParameter(ptFadeTime));
|
|
}
|
|
|
|
cViewElement::~cViewElement() {
|
|
CancelSave();
|
|
}
|
|
|
|
void cViewElement::Action(void) {
|
|
SetInitFinished();
|
|
DoSleep(delay);
|
|
Render();
|
|
FadeIn();
|
|
DoFlush();
|
|
if (scrolling) {
|
|
DoSleep(scrollDelay);
|
|
if (scrollOrientation == orHorizontal) {
|
|
ScrollHorizontal(scrollingPix, scrollDelay, scrollSpeed, scrollMode);
|
|
} else {
|
|
ScrollVertical(scrollingPix, scrollDelay, scrollSpeed);
|
|
}
|
|
}
|
|
}
|
|
|
|
void cViewElement::ClearTokens(void) {
|
|
stringTokens.clear();
|
|
intTokens.clear();
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* cViewListItem
|
|
************************************************************************/
|
|
|
|
cViewListItem::cViewListItem(cTemplateViewElement *tmplItem) : cView(tmplItem) {
|
|
pos = -1;
|
|
numTotal = 0;
|
|
align = alLeft;
|
|
listOrientation = orVertical;
|
|
}
|
|
|
|
cViewListItem::~cViewListItem() {
|
|
|
|
}
|
|
|
|
cRect cViewListItem::DrawListItem(map <string,string> *stringTokens, map <string,int> *intTokens) {
|
|
cRect posItem;
|
|
if (!tmplViewElement)
|
|
return posItem;
|
|
|
|
if (tmplViewElement->DebugTokens()) {
|
|
DebugTokens("ListItem", stringTokens, intTokens);
|
|
}
|
|
|
|
tmplViewElement->InitIterator();
|
|
cTemplatePixmap *pix = NULL;
|
|
int pixCurrent = 0;
|
|
|
|
while(pix = tmplViewElement->GetNextPixmap()) {
|
|
SetListElementPosition(pix);
|
|
if (pixCurrent == 0) {
|
|
posItem = pix->GetPixmapSize();
|
|
}
|
|
if (!PixmapExists(pixCurrent)) {
|
|
pix->ParseDynamicParameters(intTokens, true);
|
|
} else {
|
|
pix->ParseDynamicParameters(intTokens, false);
|
|
}
|
|
if (!PixmapExists(pixCurrent) && pix->Ready() && pix->DoExecute() && !pix->Scrolling()) {
|
|
CreateViewPixmap(pixCurrent, pix);
|
|
}
|
|
//if pixmap still not valid, skip
|
|
if (!pix->Ready() && !pix->Scrolling()) {
|
|
pixCurrent++;
|
|
continue;
|
|
}
|
|
//if condition for pixmap set, check if cond is true
|
|
if (!pix->DoExecute()) {
|
|
pixCurrent++;
|
|
continue;
|
|
}
|
|
|
|
pix->ClearDynamicFunctionParameters();
|
|
pix->ParseDynamicFunctionParameters(stringTokens, intTokens);
|
|
|
|
if (!PixmapExists(pixCurrent) && pix->Scrolling()) {
|
|
cSize drawportSize;
|
|
scrolling = pix->CalculateDrawPortSize(drawportSize);
|
|
pix->SetScrollingTextWidth();
|
|
if (scrolling) {
|
|
CreateScrollingPixmap(pixCurrent, pix, drawportSize);
|
|
scrollingPix = pixCurrent;
|
|
scrollOrientation = pix->GetNumericParameter(ptOrientation);
|
|
scrollMode = pix->GetNumericParameter(ptScrollMode);
|
|
scrollDelay = pix->GetNumericParameter(ptDelay);
|
|
scrollSpeed = pix->GetNumericParameter(ptScrollSpeed);
|
|
} else {
|
|
CreateViewPixmap(pixCurrent, pix);
|
|
}
|
|
}
|
|
if (pix->DoDebug()) {
|
|
pix->Debug();
|
|
}
|
|
DrawPixmap(pixCurrent, pix);
|
|
pixCurrent++;
|
|
}
|
|
return posItem;
|
|
}
|
|
|
|
void cViewListItem::ClearListItem(void) {
|
|
int pixMax = NumPixmaps();
|
|
for (int pixCurrent = 0; pixCurrent < pixMax; pixCurrent++) {
|
|
Fill(pixCurrent, clrTransparent);
|
|
}
|
|
}
|
|
|
|
void cViewListItem::SetListElementPosition(cTemplatePixmap *pix) {
|
|
int itemWidth = pix->GetNumericParameter(ptWidth);
|
|
int itemHeight = pix->GetNumericParameter(ptHeight);
|
|
int x = 0;
|
|
int y = 0;
|
|
if (listOrientation == orHorizontal) {
|
|
x = container.X();
|
|
int totalWidth = numTotal * itemWidth;
|
|
if (align == alCenter) {
|
|
y += (container.Width() - totalWidth) / 2;
|
|
} else if (align == alBottom) {
|
|
y += (container.Width() - totalWidth);
|
|
}
|
|
x += pos * itemWidth;
|
|
y = pix->GetNumericParameter(ptY);
|
|
} else if (listOrientation == orVertical) {
|
|
y = container.Y();
|
|
int totalHeight = numTotal * itemHeight;
|
|
if (align == alCenter) {
|
|
y += (container.Height() - totalHeight) / 2;
|
|
} else if (align == alBottom) {
|
|
y += (container.Height() - totalHeight);
|
|
}
|
|
y += pos * itemHeight;
|
|
x = pix->GetNumericParameter(ptX);
|
|
}
|
|
pix->SetX(x);
|
|
pix->SetY(y);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* cGrid
|
|
************************************************************************/
|
|
|
|
cGrid::cGrid(cTemplateViewElement *tmplGrid) : cView(tmplGrid) {
|
|
dirty = true;
|
|
moved = true;
|
|
resized = true;
|
|
current = false;
|
|
x = 0.0;
|
|
y = 0.0;
|
|
width = 0.0;
|
|
height = 0.0;
|
|
}
|
|
|
|
cGrid::~cGrid() {
|
|
|
|
}
|
|
|
|
void cGrid::Set(double x, double y, double width, double height,
|
|
map <string,int> *intTokens, map <string,string> *stringTokens) {
|
|
|
|
if ((width != this->width) || (height != this->height)) {
|
|
this->width = width;
|
|
this->height = height;
|
|
resized = true;
|
|
dirty = false;
|
|
} else {
|
|
resized = false;
|
|
}
|
|
if (this->x != x || this->y != y) {
|
|
this->x = x;
|
|
this->y = y;
|
|
moved = true;
|
|
} else {
|
|
moved = false;
|
|
}
|
|
if (intTokens) {
|
|
this->intTokens = *intTokens;
|
|
SetCurrent(current);
|
|
dirty = true;
|
|
}
|
|
if (stringTokens) {
|
|
this->stringTokens = *stringTokens;
|
|
dirty = true;
|
|
}
|
|
}
|
|
|
|
void cGrid::SetCurrent(bool current) {
|
|
this->current = current;
|
|
if (!resized)
|
|
dirty = true;
|
|
intTokens.erase("current");
|
|
intTokens.insert(pair<string,int>("current", current));
|
|
}
|
|
|
|
void cGrid::Move(void) {
|
|
if (!tmplViewElement)
|
|
return;
|
|
tmplViewElement->InitIterator();
|
|
cTemplatePixmap *pix = NULL;
|
|
int pixCurrent = 0;
|
|
|
|
while(pix = tmplViewElement->GetNextPixmap()) {
|
|
PositionPixmap(pix);
|
|
cRect pixViewPort = pix->GetPixmapSize();
|
|
SetViewPort(pixCurrent, pixViewPort);
|
|
pixCurrent++;
|
|
}
|
|
dirty = false;
|
|
resized = false;
|
|
moved = false;
|
|
}
|
|
|
|
void cGrid::Draw(void) {
|
|
if (!tmplViewElement)
|
|
return;
|
|
if (tmplViewElement->DebugTokens()) {
|
|
DebugTokens("Grid", &stringTokens, &intTokens);
|
|
}
|
|
|
|
tmplViewElement->InitIterator();
|
|
cTemplatePixmap *pix = NULL;
|
|
int pixCurrent = 0;
|
|
|
|
while(pix = tmplViewElement->GetNextPixmap()) {
|
|
PositionPixmap(pix);
|
|
if (!PixmapExists(pixCurrent)) {
|
|
pix->ParseDynamicParameters(&intTokens, true);
|
|
} else {
|
|
pix->ParseDynamicParameters(&intTokens, false);
|
|
}
|
|
if (!PixmapExists(pixCurrent) && pix->Ready() && pix->DoExecute() && !pix->Scrolling()) {
|
|
CreateViewPixmap(pixCurrent, pix);
|
|
}
|
|
//if pixmap still not valid, skip
|
|
if (!pix->Ready() && !pix->Scrolling()) {
|
|
pixCurrent++;
|
|
continue;
|
|
}
|
|
//if condition for pixmap set, check if cond is true
|
|
if (!pix->DoExecute()) {
|
|
pixCurrent++;
|
|
continue;
|
|
}
|
|
|
|
pix->ClearDynamicFunctionParameters();
|
|
pix->ParseDynamicFunctionParameters(&stringTokens, &intTokens);
|
|
//pix->Debug();
|
|
DrawPixmap(pixCurrent, pix);
|
|
pixCurrent++;
|
|
}
|
|
dirty = false;
|
|
resized = false;
|
|
moved = false;
|
|
}
|
|
|
|
void cGrid::Clear(void) {
|
|
int pixMax = NumPixmaps();
|
|
for (int pixCurrent = 0; pixCurrent < pixMax; pixCurrent++) {
|
|
Fill(pixCurrent, clrTransparent);
|
|
}
|
|
}
|
|
|
|
void cGrid::DeletePixmaps(void) {
|
|
int pixMax = NumPixmaps();
|
|
for (int pixCurrent = 0; pixCurrent < pixMax; pixCurrent++) {
|
|
DestroyPixmap(pixCurrent);
|
|
}
|
|
}
|
|
|
|
void cGrid::PositionPixmap(cTemplatePixmap *pix) {
|
|
pix->SetXPercent(x);
|
|
pix->SetYPercent(y);
|
|
pix->SetWidthPercent(width);
|
|
pix->SetHeightPercent(height);
|
|
pix->CalculateParameters();
|
|
}
|