vdr-plugin-skindesigner/coreengine/functions.c

1596 lines
58 KiB
C

#include "attribute.h"
#include "../config.h"
/***************************************************************************
* cFuncFill
***************************************************************************/
cFuncFill::cFuncFill(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "Fill";
SetAttributesDefs();
}
cFuncFill::cFuncFill(const cFuncFill &other) : cFunction(other) {
funcType = other.funcType;
}
cFuncFill::~cFuncFill(void) {
}
void cFuncFill::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func Fill attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eFillAttribs::color)) {
SetColor(attVal);
}
}
}
void cFuncFill::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("color", (int)eFillAttribs::color));
attribNames.insert(pair<int, string>((int)eFillAttribs::color, "color"));
}
void cFuncFill::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
if (!color)
return;
p->Fill(color->Color());
}
/***************************************************************************
* cFuncDrawRectangle
***************************************************************************/
cFuncDrawRectangle::cFuncDrawRectangle(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "DrawRectangle";
SetAttributesDefs();
}
cFuncDrawRectangle::cFuncDrawRectangle(const cFuncDrawRectangle &other) : cFunction(other) {
funcType = other.funcType;
}
cFuncDrawRectangle::~cFuncDrawRectangle(void) {
}
void cFuncDrawRectangle::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func DrawRectangle attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eDrawRectangleAttribs::color)) {
SetColor(attVal);
} else if (IdEqual(id, (int)eDrawRectangleAttribs::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eDrawRectangleAttribs::align)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawRectangleAttribs::valign)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawRectangleAttribs::animtype)) {
SetAnimType(id, attVal);
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncDrawRectangle::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("align", (int)eDrawRectangleAttribs::align));
attribIDs.insert(pair<string, int>("valign", (int)eDrawRectangleAttribs::valign));
attribIDs.insert(pair<string, int>("color", (int)eDrawRectangleAttribs::color));
attribIDs.insert(pair<string, int>("name", (int)eDrawRectangleAttribs::name));
attribIDs.insert(pair<string, int>("animtype", (int)eDrawRectangleAttribs::animtype));
attribIDs.insert(pair<string, int>("animfreq", (int)eDrawRectangleAttribs::animfreq));
attribNames.insert(pair<int, string>((int)eDrawRectangleAttribs::align, "align"));
attribNames.insert(pair<int, string>((int)eDrawRectangleAttribs::valign, "valign"));
attribNames.insert(pair<int, string>((int)eDrawRectangleAttribs::color, "color"));
attribNames.insert(pair<int, string>((int)eDrawRectangleAttribs::name, "name"));
attribNames.insert(pair<int, string>((int)eDrawRectangleAttribs::animtype, "animtype"));
attribNames.insert(pair<int, string>((int)eDrawRectangleAttribs::animfreq, "animfreq"));
}
void cFuncDrawRectangle::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
eAlign align = (eAlign)GetValue((int)eDrawRectangleAttribs::align);
eAlign valign = (eAlign)GetValue((int)eDrawRectangleAttribs::valign);
int x = GetX(align, x0, colWidth);
int y = GetY(valign, y0, rowHeight);
cRect rect(x, y, Width(), Height());
p->DrawRectangle(rect, color->Color());
}
/***************************************************************************
* cFuncDrawEllipse
***************************************************************************/
cFuncDrawEllipse::cFuncDrawEllipse(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "DrawEllipse";
SetAttributesDefs();
}
cFuncDrawEllipse::cFuncDrawEllipse(const cFuncDrawEllipse &other) : cFunction(other) {
funcType = other.funcType;
}
cFuncDrawEllipse::~cFuncDrawEllipse(void) {
}
void cFuncDrawEllipse::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func DrawEllipse attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eDrawEllipseAttribs::color)) {
SetColor(attVal);
} else if (IdEqual(id, (int)eDrawEllipseAttribs::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eDrawEllipseAttribs::align)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawEllipseAttribs::valign)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawEllipseAttribs::animtype)) {
SetAnimType(id, attVal);
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncDrawEllipse::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("align", (int)eDrawEllipseAttribs::align));
attribIDs.insert(pair<string, int>("valign", (int)eDrawEllipseAttribs::valign));
attribIDs.insert(pair<string, int>("color", (int)eDrawEllipseAttribs::color));
attribIDs.insert(pair<string, int>("name", (int)eDrawEllipseAttribs::name));
attribIDs.insert(pair<string, int>("quadrant", (int)eDrawEllipseAttribs::quadrant));
attribIDs.insert(pair<string, int>("animtype", (int)eDrawEllipseAttribs::animtype));
attribIDs.insert(pair<string, int>("animfreq", (int)eDrawEllipseAttribs::animfreq));
attribNames.insert(pair<int, string>((int)eDrawEllipseAttribs::align, "align"));
attribNames.insert(pair<int, string>((int)eDrawEllipseAttribs::valign, "valign"));
attribNames.insert(pair<int, string>((int)eDrawEllipseAttribs::color, "color"));
attribNames.insert(pair<int, string>((int)eDrawEllipseAttribs::name, "name"));
attribNames.insert(pair<int, string>((int)eDrawEllipseAttribs::quadrant, "quadrant"));
attribNames.insert(pair<int, string>((int)eDrawEllipseAttribs::animtype, "animtype"));
attribNames.insert(pair<int, string>((int)eDrawEllipseAttribs::animfreq, "animfreq"));
}
void cFuncDrawEllipse::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
eAlign align = (eAlign)GetValue((int)eDrawEllipseAttribs::align);
eAlign valign = (eAlign)GetValue((int)eDrawEllipseAttribs::valign);
int x = GetX(align, x0, colWidth);
int y = GetY(valign, y0, rowHeight);
cRect rect(x, y, Width(), Height());
int quadrant = GetValue((int)eDrawEllipseAttribs::quadrant);
p->DrawEllipse(rect, color->Color(), quadrant);
}
/***************************************************************************
* cFuncDrawSlope
***************************************************************************/
cFuncDrawSlope::cFuncDrawSlope(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "DrawSlope";
SetAttributesDefs();
}
cFuncDrawSlope::cFuncDrawSlope(const cFuncDrawSlope &other) : cFunction(other) {
funcType = other.funcType;
}
cFuncDrawSlope::~cFuncDrawSlope(void) {
}
void cFuncDrawSlope::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func DrawSlope attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eDrawSlopeAttribs::color)) {
SetColor(attVal);
} else if (IdEqual(id, (int)eDrawSlopeAttribs::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eDrawSlopeAttribs::align)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawSlopeAttribs::valign)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawSlopeAttribs::animtype)) {
SetAnimType(id, attVal);
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncDrawSlope::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("align", (int)eDrawSlopeAttribs::align));
attribIDs.insert(pair<string, int>("valign", (int)eDrawSlopeAttribs::valign));
attribIDs.insert(pair<string, int>("color", (int)eDrawSlopeAttribs::color));
attribIDs.insert(pair<string, int>("name", (int)eDrawSlopeAttribs::name));
attribIDs.insert(pair<string, int>("type", (int)eDrawSlopeAttribs::type));
attribIDs.insert(pair<string, int>("animtype", (int)eDrawSlopeAttribs::animtype));
attribIDs.insert(pair<string, int>("animfreq", (int)eDrawSlopeAttribs::animfreq));
attribNames.insert(pair<int, string>((int)eDrawSlopeAttribs::align, "align"));
attribNames.insert(pair<int, string>((int)eDrawSlopeAttribs::valign, "valign"));
attribNames.insert(pair<int, string>((int)eDrawSlopeAttribs::color, "color"));
attribNames.insert(pair<int, string>((int)eDrawSlopeAttribs::name, "name"));
attribNames.insert(pair<int, string>((int)eDrawSlopeAttribs::type, "type"));
attribNames.insert(pair<int, string>((int)eDrawSlopeAttribs::animtype, "animtype"));
attribNames.insert(pair<int, string>((int)eDrawSlopeAttribs::animfreq, "animfreq"));
}
void cFuncDrawSlope::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
eAlign align = (eAlign)GetValue((int)eDrawSlopeAttribs::align);
eAlign valign = (eAlign)GetValue((int)eDrawSlopeAttribs::valign);
int x = GetX(align, x0, colWidth);
int y = GetY(valign, y0, rowHeight);
cRect rect(x, y, Width(), Height());
int type = GetValue((int)eDrawSlopeAttribs::type);
p->DrawSlope(rect, color->Color(), type);
}
/***************************************************************************
* cTextDrawer
***************************************************************************/
cMutex cTextDrawer::fontLock;
cTextDrawer::cTextDrawer(void) {
font = NULL;
fontName = NULL;
fontSize = 0;
}
cTextDrawer::~cTextDrawer(void) {
free(fontName);
}
void cTextDrawer::CacheFont(cGlobals *globals, int size) {
//check if font name is a global token
if (startswith(fontName, "{") && endswith(fontName, "}")) {
string tmpFontName = "";
if (globals->GetFont(fontName, tmpFontName)) {
free(fontName);
fontName = strdup(tmpFontName.c_str());
} else {
esyslog("skindesigner: unknown font %s", fontName);
return;
}
}
if (size > 0)
LoadFont(size);
}
void cTextDrawer::LoadFont(int size) {
if (!fontName)
return;
if (size <= 0)
return;
font = fontManager->Font(fontName, size);
if (font)
fontSize = size;
}
int cTextDrawer::TextWidth(const char *text) {
int textWidth = 0;
fontLock.Lock();
textWidth = font->Width(text);
fontLock.Unlock();
return textWidth;
}
int cTextDrawer::FontHeight(void) {
int fontHeight = 0;
fontLock.Lock();
fontHeight = font->Height();
fontLock.Unlock();
return fontHeight;
}
/***************************************************************************
* cFuncDrawText
***************************************************************************/
cFuncDrawText::cFuncDrawText(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "DrawText";
text = NULL;
SetAttributesDefs();
}
cFuncDrawText::cFuncDrawText(const cFuncDrawText &other) : cFunction(other) {
funcType = other.funcType;
fontName = NULL;
if (other.fontName)
fontName = strdup(other.fontName);
font = other.font;
text = NULL;
if (other.text)
text = new cTextExpr(*other.text);
}
cFuncDrawText::~cFuncDrawText(void) {
delete text;
}
void cFuncDrawText::SetLoopInfo(cLoopInfo *loopInfo) {
cFunction::SetLoopInfo(loopInfo);
if (text)
text->SetLoopInfo(loopInfo);
}
void cFuncDrawText::SetTokenContainerDeep(skindesignerapi::cTokenContainer *tokenContainer) {
cAttributes::SetTokenContainerDeep(tokenContainer);
if (text) {
text->SetTokenContainer(tokenContainer);
}
}
void cFuncDrawText::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func DrawText attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eDrawTextAttribs::color)) {
SetColor(attVal);
} else if (IdEqual(id, (int)eDrawTextAttribs::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eDrawTextAttribs::align)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawTextAttribs::valign)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawTextAttribs::animtype)) {
SetAnimType(id, attVal);
} else if (IdEqual(id, (int)eDrawTextAttribs::font)) {
fontName = strdup(attVal);
} else if (IdEqual(id, (int)eDrawTextAttribs::text)) {
text = new cTextExpr(attVal);
} else if (IdEqual(id, (int)eDrawTextAttribs::fontsize)) {
attribCtors[id] = new cNumericExpr(attVal);
attribCtors[id]->SetVertical();
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncDrawText::Cache(void) {
cFunction::Cache();
if (text) {
text->SetTokenContainer(tokenContainer);
text->SetGlobals(globals);
text->Cache();
}
if (fontName) {
CacheFont(globals, GetValue((int)eDrawTextAttribs::fontsize));
}
}
void cFuncDrawText::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
if (!font) {
LoadFont(GetValue((int)eDrawTextAttribs::fontsize));
if (!font)
return;
}
char *funcText = NULL;
if (text)
funcText = text->DeterminateText();
if (!funcText)
return;
int maxTextWidth = Width();
if (maxTextWidth > 0 && !scrolling) {
if (TextWidth(funcText) > maxTextWidth) {
funcText = Cut(funcText, maxTextWidth);
}
} else if (!scrolling) {
maxTextWidth = container.Width() - X();
if (TextWidth(funcText) > maxTextWidth) {
funcText = Cut(funcText, maxTextWidth);
}
}
eAlign horAlign = (eAlign)GetValue((int)eDrawTextAttribs::align);
eAlign verAlign = (eAlign)GetValue((int)eDrawTextAttribs::valign);
int contWidth = colWidth > 0 ? colWidth : container.Width();
int x = X() + x0;
if (horAlign == eAlign::right) {
x = x0 + contWidth - TextWidth(funcText);
} else if (horAlign == eAlign::center) {
x = x0 + (contWidth - TextWidth(funcText)) / 2;
}
if (x < 0) x = 0;
int contHeight = rowHeight > 0 ? rowHeight : container.Height();
int y = Y() + y0;
if (verAlign == eAlign::bottom) {
y = y0 + contHeight - FontHeight();
} else if (verAlign == eAlign::center) {
y = y0 + (contHeight - FontHeight()) / 2;
}
p->DrawText(cPoint(x, y), funcText, color->Color(), clrTransparent, font);
free(funcText);
}
int cFuncDrawText::FuncX(void) {
if (!font)
return 0;
char *funcText = NULL;
if (text)
funcText = text->DeterminateText();
if (!funcText)
return 0;
eAlign horAlign = (eAlign)GetValue((int)eDrawTextAttribs::align);
int x = X();
if (horAlign == eAlign::right) {
x = container.Width() - TextWidth(funcText);
} else if (horAlign == eAlign::center) {
x = (container.Width() - TextWidth(funcText)) / 2;
}
return (x >= 0) ? x : 0 ;
}
int cFuncDrawText::FuncY(void) {
if (!font)
return 0;
eAlign verAlign = (eAlign)GetValue((int)eDrawTextAttribs::valign);
int y = Y();
if (verAlign == eAlign::bottom) {
y = container.Height() - FontHeight();
} else if (verAlign == eAlign::center) {
y = (container.Height() - FontHeight()) / 2;
}
return y;
}
int cFuncDrawText::FuncWidth(void) {
if (!font)
return 0;
char *funcText = NULL;
if (text)
funcText = text->DeterminateText();
if (!funcText)
return 0;
int textWidth = TextWidth(funcText);
free(funcText);
return textWidth;
}
int cFuncDrawText::FuncHeight(void) {
if (!font)
return 0;
return FontHeight();
}
int cFuncDrawText::AvrgFontWidth(void) {
if (!font)
return 20;
return TextWidth("x")+3;
}
const cFont *cFuncDrawText::GetFont(void) {
return font;
}
void cFuncDrawText::Debug(void) {
cFunction::Debug();
if (fontName)
esyslog("skindesigner: fontname: \"%s\"", fontName);
if (font)
esyslog("skindesigner: cached font name: \"%s\", size %d", font->FontName(), font->Height());
if (text)
text->Debug("draw text");
}
void cFuncDrawText::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("align", (int)eDrawTextAttribs::align));
attribIDs.insert(pair<string, int>("valign", (int)eDrawTextAttribs::valign));
attribIDs.insert(pair<string, int>("color", (int)eDrawTextAttribs::color));
attribIDs.insert(pair<string, int>("font", (int)eDrawTextAttribs::font));
attribIDs.insert(pair<string, int>("fontsize", (int)eDrawTextAttribs::fontsize));
attribIDs.insert(pair<string, int>("name", (int)eDrawTextAttribs::name));
attribIDs.insert(pair<string, int>("text", (int)eDrawTextAttribs::text));
attribIDs.insert(pair<string, int>("animtype", (int)eDrawTextAttribs::animtype));
attribIDs.insert(pair<string, int>("animfreq", (int)eDrawTextAttribs::animfreq));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::align, "align"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::valign, "valign"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::color, "color"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::font, "font"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::fontsize, "fontsize"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::name, "name"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::text, "text"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::animtype, "animtype"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribs::animfreq, "animfreq"));
}
char *cFuncDrawText::Cut(char *expr, int width) {
char *cutted = NULL;
int w = 3 * font->Width(".");
for (char *p = expr; *p; ) {
int sl = Utf8CharLen(p);
uint sym = Utf8CharGet(p, sl);
w += font->Width(sym);
if( w >= width ) {
cutted = (char*)malloc(p - expr + 4);
memset(cutted, 0, p - expr + 4);
strncpy(cutted, expr, p - expr);
cutted[p - expr] = '.';
cutted[p - expr + 1] = '.';
cutted[p - expr + 2] = '.';
break;
}
p += sl;
}
if (cutted) {
free(expr);
return cutted;
}
return expr;
}
/***************************************************************************
* cFuncDrawTextVertical
***************************************************************************/
cFuncDrawTextVertical::cFuncDrawTextVertical(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "DrawTextVertical";
text = NULL;
SetAttributesDefs();
}
cFuncDrawTextVertical::cFuncDrawTextVertical(const cFuncDrawTextVertical &other) : cFunction(other) {
funcType = other.funcType;
fontName = NULL;
if (other.fontName)
fontName = strdup(other.fontName);
text = NULL;
if (other.text)
text = new cTextExpr(*other.text);
}
cFuncDrawTextVertical::~cFuncDrawTextVertical(void) {
delete text;
}
void cFuncDrawTextVertical::SetLoopInfo(cLoopInfo *loopInfo) {
cFunction::SetLoopInfo(loopInfo);
if (text)
text->SetLoopInfo(loopInfo);
}
void cFuncDrawTextVertical::SetTokenContainerDeep(skindesignerapi::cTokenContainer *tokenContainer) {
cAttributes::SetTokenContainerDeep(tokenContainer);
if (text) {
text->SetTokenContainer(tokenContainer);
}
}
void cFuncDrawTextVertical::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func DrawTextVertical attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eDrawTextAttribsVertical::color)) {
SetColor(attVal);
} else if (IdEqual(id, (int)eDrawTextAttribsVertical::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eDrawTextAttribsVertical::align)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawTextAttribsVertical::direction)) {
SetDirection(id, attVal);
} else if (IdEqual(id, (int)eDrawTextAttribsVertical::valign)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawTextAttribsVertical::animtype)) {
SetAnimType(id, attVal);
} else if (IdEqual(id, (int)eDrawTextAttribsVertical::font)) {
fontName = strdup(attVal);
} else if (IdEqual(id, (int)eDrawTextAttribsVertical::text)) {
text = new cTextExpr(attVal);
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncDrawTextVertical::Cache(void) {
cFunction::Cache();
if (text) {
text->SetTokenContainer(tokenContainer);
text->SetGlobals(globals);
text->Cache();
}
if (fontName) {
CacheFont(globals, 0);
}
}
void cFuncDrawTextVertical::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
char *funcText = NULL;
if (text)
funcText = text->DeterminateText();
if (!funcText)
return;
int fontSize = GetValue((int)eDrawTextAttribsVertical::fontsize);
int direction = GetValue((int)eDrawTextAttribsVertical::direction);
tColor clr = color->Color();
cImage *textVertical = imgCache->GetVerticalText(funcText, clr, fontName, fontSize, direction);
if (!textVertical)
return;
eAlign horAlign = (eAlign)GetValue((int)eDrawTextAttribsVertical::align);
eAlign verAlign = (eAlign)GetValue((int)eDrawTextAttribsVertical::valign);
int x = 0;
int y = 0;
if (horAlign == eAlign::center) {
x = (container.Width() - textVertical->Width()) / 2;
} else if (horAlign == eAlign::right) {
x = container.Width() - textVertical->Width();
}
if (verAlign == eAlign::center) {
y = (container.Height() - textVertical->Height()) / 2;
} else if (horAlign == eAlign::bottom) {
y = container.Height() - textVertical->Height();
}
cPoint pos(x, y);
p->DrawImage(pos, *textVertical);
free(funcText);
}
int cFuncDrawTextVertical::FuncWidth(void) {
char *funcText = NULL;
if (text)
funcText = text->DeterminateText();
if (!funcText)
return 0;
int fontSize = GetValue((int)eDrawTextAttribsVertical::fontsize);
int direction = GetValue((int)eDrawTextAttribsVertical::direction);
tColor clr = color->Color();
cImage *textVertical = imgCache->GetVerticalText(funcText, clr, fontName, fontSize, direction);
if (!textVertical)
return 0;
return textVertical->Width();
}
int cFuncDrawTextVertical::FuncHeight(void) {
char *funcText = NULL;
if (text)
funcText = text->DeterminateText();
if (!funcText)
return 0;
int fontSize = GetValue((int)eDrawTextAttribsVertical::fontsize);
int direction = GetValue((int)eDrawTextAttribsVertical::direction);
tColor clr = color->Color();
cImage *textVertical = imgCache->GetVerticalText(funcText, clr, fontName, fontSize, direction);
if (!textVertical)
return 0;
return textVertical->Height();
}
void cFuncDrawTextVertical::Debug(void) {
cFunction::Debug();
if (fontName)
esyslog("skindesigner: fontname: \"%s\"", fontName);
if (text)
text->Debug("draw text");
}
void cFuncDrawTextVertical::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("align", (int)eDrawTextAttribsVertical::align));
attribIDs.insert(pair<string, int>("valign", (int)eDrawTextAttribsVertical::valign));
attribIDs.insert(pair<string, int>("direction", (int)eDrawTextAttribsVertical::direction));
attribIDs.insert(pair<string, int>("color", (int)eDrawTextAttribsVertical::color));
attribIDs.insert(pair<string, int>("font", (int)eDrawTextAttribsVertical::font));
attribIDs.insert(pair<string, int>("fontsize", (int)eDrawTextAttribsVertical::fontsize));
attribIDs.insert(pair<string, int>("name", (int)eDrawTextAttribsVertical::name));
attribIDs.insert(pair<string, int>("text", (int)eDrawTextAttribsVertical::text));
attribIDs.insert(pair<string, int>("animtype", (int)eDrawTextAttribsVertical::animtype));
attribIDs.insert(pair<string, int>("animfreq", (int)eDrawTextAttribsVertical::animfreq));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::align, "align"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::valign, "valign"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::direction, "direction"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::color, "color"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::font, "font"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::fontsize, "fontsize"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::name, "name"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::text, "text"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::animtype, "animtype"));
attribNames.insert(pair<int, string>((int)eDrawTextAttribsVertical::animfreq, "animfreq"));
}
/***************************************************************************
* cFuncDrawTextBox
***************************************************************************/
cFuncDrawTextBox::cFuncDrawTextBox(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "DrawTextBox";
text = NULL;
floater = NULL;
SetAttributesDefs();
}
cFuncDrawTextBox::cFuncDrawTextBox(const cFuncDrawTextBox &other) : cFunction(other) {
funcType = other.funcType;
fontName = NULL;
if (other.fontName)
fontName = strdup(other.fontName);
font = other.font;
text = NULL;
if (other.text)
text = new cTextExpr(*other.text);
floater = NULL;
}
cFuncDrawTextBox::~cFuncDrawTextBox(void) {
delete text;
delete floater;
}
void cFuncDrawTextBox::SetLoopInfo(cLoopInfo *loopInfo) {
cFunction::SetLoopInfo(loopInfo);
if (text)
text->SetLoopInfo(loopInfo);
}
void cFuncDrawTextBox::SetTokenContainerDeep(skindesignerapi::cTokenContainer *tokenContainer) {
cAttributes::SetTokenContainerDeep(tokenContainer);
if (text) {
text->SetTokenContainer(tokenContainer);
}
}
void cFuncDrawTextBox::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func DrawTextBox attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eDrawTextBoxAttribs::color)) {
SetColor(attVal);
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::align)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::valign)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::floatmode)) {
SetFloatMode(id, attVal);
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::floatheight)) {
attribCtors[id] = new cNumericExpr(attVal);
attribCtors[id]->SetVertical();
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::font)) {
fontName = strdup(attVal);
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::text)) {
text = new cTextExpr(attVal);
} else if (IdEqual(id, (int)eDrawTextBoxAttribs::fontsize)) {
attribCtors[id] = new cNumericExpr(attVal);
attribCtors[id]->SetVertical();
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncDrawTextBox::Cache(void) {
cFunction::Cache();
if (text) {
text->SetTokenContainer(tokenContainer);
text->SetGlobals(globals);
text->Cache();
}
if (fontName) {
CacheFont(globals, GetValue((int)eDrawTextBoxAttribs::fontsize));
}
}
void cFuncDrawTextBox::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
if (!font) {
LoadFont(GetValue((int)eDrawTextBoxAttribs::fontsize));
if (!font)
return;
}
SetFloater();
eFloatMode mode = (eFloatMode)GetValue((int)eDrawTextBoxAttribs::floatmode);
int fontHeight = FontHeight();
int lines = floater->Lines();
eAlign align = (eAlign)GetValue((int)eDrawTextBoxAttribs::align);
int boxX = X() + x0;
int floatHeight = 0;
if ( mode == eFloatMode::topleft ) {
boxX += GetValue((int)eDrawTextBoxAttribs::floatwidth);
floatHeight = GetValue((int)eDrawTextBoxAttribs::floatheight);
}
eAlign valign = (eAlign)GetValue((int)eDrawTextBoxAttribs::valign);
int height = Height();
if (height <= 0)
height = container.Height();
int y = Y() + y0;
if (valign == eAlign::center) {
y = y0 + (height - fontHeight * lines) / 2;
} else if (valign == eAlign::bottom) {
y = y0 + height - fontHeight * lines;
}
int x = boxX;
for (int line=0; line < lines; line++) {
const char *lineText = floater->GetLine(line);
if (!lineText)
break;
if (align == eAlign::center) {
x = boxX + (Width() - TextWidth(lineText)) / 2;
} else if (align == eAlign::right) {
x = boxX + Width() - TextWidth(lineText);
}
p->DrawText(cPoint(x, y), lineText, color->Color(), clrTransparent, font);
y += fontHeight;
if ( mode == eFloatMode::topleft ) {
if ((line+1) * fontHeight >= floatHeight)
x = X() + x0;
}
}
}
int cFuncDrawTextBox::FuncWidth(void) {
return Width();
}
int cFuncDrawTextBox::FuncHeight(void) {
if (!font)
return 0;
int boxHeight = Height();
if (boxHeight > 0)
return boxHeight;
SetFloater();
int lines = floater->Lines();
return lines * FontHeight();
}
void cFuncDrawTextBox::Debug(void) {
cFunction::Debug();
if (fontName)
esyslog("skindesigner: fontname: \"%s\"", fontName);
if (font)
esyslog("skindesigner: cached font name: \"%s\", size %d", font->FontName(), font->Height());
if (text)
text->Debug("draw textbox");
}
void cFuncDrawTextBox::SetFloater(void) {
char *funcText = NULL;
if (text)
funcText = text->DeterminateText();
int boxWidth = Width();
int boxHeight = Height();
int floatWidth = GetValue((int)eDrawTextBoxAttribs::floatwidth);
int floatHeight = GetValue((int)eDrawTextBoxAttribs::floatheight);
int maxLines = GetValue((int)eDrawTextBoxAttribs::maxlines);
delete floater;
floater = new cTextFloater();
floater->Set(funcText, font, boxWidth, boxHeight, floatWidth, floatHeight, maxLines);
free(funcText);
}
void cFuncDrawTextBox::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("align", (int)eDrawTextBoxAttribs::align));
attribIDs.insert(pair<string, int>("valign", (int)eDrawTextBoxAttribs::valign));
attribIDs.insert(pair<string, int>("maxlines", (int)eDrawTextBoxAttribs::maxlines));
attribIDs.insert(pair<string, int>("floatwidth", (int)eDrawTextBoxAttribs::floatwidth));
attribIDs.insert(pair<string, int>("floatheight", (int)eDrawTextBoxAttribs::floatheight));
attribIDs.insert(pair<string, int>("float", (int)eDrawTextBoxAttribs::floatmode));
attribIDs.insert(pair<string, int>("color", (int)eDrawTextBoxAttribs::color));
attribIDs.insert(pair<string, int>("font", (int)eDrawTextBoxAttribs::font));
attribIDs.insert(pair<string, int>("fontsize", (int)eDrawTextBoxAttribs::fontsize));
attribIDs.insert(pair<string, int>("name", (int)eDrawTextBoxAttribs::name));
attribIDs.insert(pair<string, int>("text", (int)eDrawTextBoxAttribs::text));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::align, "align"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::valign, "valign"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::maxlines, "maxlines"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::floatwidth, "floatwidth"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::floatheight, "floatheight"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::floatmode, "float"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::color, "color"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::font, "font"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::fontsize, "fontsize"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::name, "name"));
attribNames.insert(pair<int, string>((int)eDrawTextBoxAttribs::text, "text"));
}
void cFuncDrawTextBox::SetFloatMode(int id, const char *val) {
eFloatMode mode = eFloatMode::none;
if (!strcmp(val, "topleft"))
mode = eFloatMode::topleft;
else if (!strcmp(val, "topright"))
mode = eFloatMode::topright;
attribs[id] = (int)mode;
}
/***************************************************************************
* cFuncDrawImage
***************************************************************************/
cFuncDrawImage::cFuncDrawImage(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "DrawImage";
path = NULL;
SetAttributesDefs();
}
cFuncDrawImage::cFuncDrawImage(const cFuncDrawImage &other) : cFunction(other) {
funcType = other.funcType;
path = NULL;
if (other.path)
path = new cTextExpr(*other.path);
}
cFuncDrawImage::~cFuncDrawImage(void) {
delete path;
}
void cFuncDrawImage::SetLoopInfo(cLoopInfo *loopInfo) {
cFunction::SetLoopInfo(loopInfo);
if (path)
path->SetLoopInfo(loopInfo);
}
void cFuncDrawImage::SetTokenContainerDeep(skindesignerapi::cTokenContainer *tokenContainer) {
cAttributes::SetTokenContainerDeep(tokenContainer);
if (path) {
path->SetTokenContainer(tokenContainer);
}
}
void cFuncDrawImage::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown func DrawText attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eDrawImageAttribs::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eDrawImageAttribs::path)) {
path = new cTextExpr(attVal);
} else if (IdEqual(id, (int)eDrawImageAttribs::align)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawImageAttribs::valign)) {
SetAlign(id, attVal);
} else if (IdEqual(id, (int)eDrawImageAttribs::imagetype)) {
SetImageType(id, attVal);
} else if (IdEqual(id, (int)eDrawImageAttribs::animtype)) {
SetAnimType(id, attVal);
} else if (IdEqual(id, (int)eDrawImageAttribs::cache)) {
SetBool(id, attVal);
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncDrawImage::Debug(void) {
cFunction::Debug();
if (path)
path->Debug("image path");
}
void cFuncDrawImage::SetImageType(int id, const char *val) {
eImageType imgType = eImageType::image;
if (!strcmp(val, "channellogo"))
imgType = eImageType::channellogo;
else if (!strcmp(val, "seplogo"))
imgType = eImageType::seplogo;
else if (!strcmp(val, "skinpart"))
imgType = eImageType::skinpart;
else if (!strcmp(val, "menuicon"))
imgType = eImageType::menuicon;
else if (!strcmp(val, "icon"))
imgType = eImageType::icon;
attribs[id] = (int)imgType;
}
void cFuncDrawImage::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("align", (int)eDrawImageAttribs::align));
attribIDs.insert(pair<string, int>("valign", (int)eDrawImageAttribs::valign));
attribIDs.insert(pair<string, int>("imagetype", (int)eDrawImageAttribs::imagetype));
attribIDs.insert(pair<string, int>("name", (int)eDrawImageAttribs::name));
attribIDs.insert(pair<string, int>("cache", (int)eDrawImageAttribs::cache));
attribIDs.insert(pair<string, int>("path", (int)eDrawImageAttribs::path));
attribIDs.insert(pair<string, int>("animtype", (int)eDrawImageAttribs::animtype));
attribIDs.insert(pair<string, int>("animfreq", (int)eDrawImageAttribs::animfreq));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::align, "align"));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::valign, "valign"));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::imagetype, "imagetype"));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::name, "name"));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::cache, "cache"));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::path, "path"));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::animtype, "animtype"));
attribNames.insert(pair<int, string>((int)eDrawImageAttribs::animfreq, "animfreq"));
}
void cFuncDrawImage::Cache(void) {
cFunction::Cache();
if (path) {
int type = GetValue((int)eDrawImageAttribs::imagetype);
if (type == (int)eImageType::image) {
path->CorrectImagePath();
}
path->SetGlobals(globals);
path->SetTokenContainer(tokenContainer);
path->Cache();
}
if (config.cacheImagesInitial)
PreCacheImage();
}
void cFuncDrawImage::PreCacheImage(void) {
int imgWidth = Width();
int imgHeight = Height();
char *imgPath = path->DeterminateText();
if (!(imgWidth > 0 && imgHeight > 0))
return;
eImageType type = (eImageType)GetValue((int)eDrawImageAttribs::imagetype);
switch (type) {
case eImageType::channellogo:
imgCache->CacheLogo(imgWidth, imgHeight);
break;
case eImageType::skinpart:
if (imgPath)
imgCache->GetSkinpart(imgPath, imgWidth, imgHeight);
break;
case eImageType::icon:
case eImageType::menuicon:
if (imgPath)
imgCache->GetIcon(type, imgPath, imgWidth, imgHeight);
break;
default:
break;
}
free(imgPath);
}
void cFuncDrawImage::Render(cPixmap *p, int x0, int y0, int colWidth, int rowHeight) {
if (!path)
return;
eAlign align = (eAlign)GetValue((int)eDrawImageAttribs::align);
eAlign valign = (eAlign)GetValue((int)eDrawImageAttribs::valign);
int x = GetX(align, x0, colWidth);
int y = GetY(valign, y0, rowHeight);
cPoint pos(x, y);
eImageType type = (eImageType)GetValue((int)eDrawImageAttribs::imagetype);
char *imgPath = path->DeterminateText();
if (!imgPath)
return;
switch (type) {
case eImageType::channellogo: {
cImage *logo = imgCache->GetLogo(imgPath, Width(), Height());
if (logo) {
p->DrawImage(pos, *logo);
}
break; }
case eImageType::seplogo: {
cImage *sep = imgCache->GetSeparatorLogo(imgPath, Width(), Height());
if (sep) {
p->DrawImage(pos, *sep);
}
break; }
case eImageType::skinpart: {
cCachedImage *img = imgCache->GetSkinpart(imgPath, Width(), Height());
if (!img) break;
if (img->handle) {
p->DrawImage(pos, img->handle);
} else if (img->image) {
p->DrawImage(pos, *(img->image));
}
break; }
case eImageType::icon:
case eImageType::menuicon: {
cCachedImage *img = imgCache->GetIcon(type, imgPath, Width(), Height());
if (!img) break;
if (img->handle) {
p->DrawImage(pos, img->handle);
} else if (img->image) {
p->DrawImage(pos, *(img->image));
}
break; }
case eImageType::image: {
cImageLoader imgLoader;
if (imgLoader.LoadImage(imgPath)) {
cImage *img = imgLoader.CreateImage(Width(), Height());
if (!img) break;
p->DrawImage(pos, *img);
delete(img);
}
break; }
}
free(imgPath);
}
/***************************************************************************
* cFuncLoop
***************************************************************************/
cFuncLoop::cFuncLoop(cArea *owner, int numAttributes) : cFunction(owner, numAttributes) {
funcType = "LoopFunc";
SetAttributesDefs();
}
cFuncLoop::~cFuncLoop(void) {
}
void cFuncLoop::Set(vector<stringpair> &attributes) {
for (vector<stringpair>::iterator att = attributes.begin(); att != attributes.end(); att++) {
const char *attName = (*att).first.c_str();
const char *attVal = (*att).second.c_str();
int id = AttributeId(attName);
if (id == ATTR_UNKNOWN) {
esyslog("skindesigner: unknown loopfunc attribute \"%s\" = \"%s\"", attName, attVal);
continue;
}
if (SetCommon(id, attVal))
continue;
if (IdEqual(id, (int)eLoopAttribs::name)) {
name = strdup(attVal);
} else if (IdEqual(id, (int)eLoopAttribs::orientation)) {
SetOrientation(id, attVal);
} else if (IdEqual(id, (int)eLoopAttribs::overflow)) {
SetOverflow(id, attVal);
} else if (IdEqual(id, (int)eLoopAttribs::valign)) {
SetAlign(id, attVal);
} else {
attribCtors[id] = new cNumericExpr(attVal);
}
}
}
void cFuncLoop::Cache(void) {
cFunction::Cache();
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
f->SetGlobals(globals);
f->SetTokenContainer(tokenContainer);
f->Cache();
}
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
f->SetLoopInfo(&loopInfo);
f->CacheFuncReferences();
}
}
void cFuncLoop::SetContainer(int x, int y, int width, int height) {
cAttributes::SetContainer(x, y, width, height);
int funcX = X();
int funcY = Y();
int funcWidth = Width();
int funcHeight = Height();
int funcContainerX = (funcX > 0) ? x + funcX : x;
int funcContainerY = (funcY > 0) ? y + funcY : y;
int funcContainerWidth = (funcWidth > 0) ? funcWidth : width;
int funcContainerHeight = (funcHeight > 0) ? funcHeight : height;
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
f->SetContainer(funcContainerX, funcContainerY, funcContainerWidth, funcContainerHeight);
}
}
void cFuncLoop::AddFunction(cFunction *f) {
functions.Add(f);
}
cFunction *cFuncLoop::GetFunction(const char *name) {
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
const char *funcName = f->Name();
if (funcName && !strcmp(funcName, name)) {
return f;
}
}
return NULL;
}
void cFuncLoop::Render(cPixmap *p, int x0, int y0, int cw, int rh) {
int loopIndex = tokenContainer->LoopIndex(Name());
if (loopIndex < 0) {
esyslog("skindesigner: unknown loop function \"%s\"", Name());
return;
}
int numRows = tokenContainer->NumLoops(loopIndex);
if (numRows < 1)
return;
int columnWidth = GetValue((int)eLoopAttribs::columnwidth);
int rowHeight = GetValue((int)eLoopAttribs::rowheight);
int maxItems = GetValue((int)eLoopAttribs::maxitems);
eOrientation orientation = (eOrientation)GetValue((int)eLoopAttribs::orientation);
eOverflowType overflow = (eOverflowType)GetValue((int)eLoopAttribs::overflow);
eAlign vAlign = (eAlign)GetValue((int)eLoopAttribs::valign);
int loopWidth = Width();
if (loopWidth <= 0)
loopWidth = container.Width();
int loopHeight = Height();
if (loopHeight <= 0)
loopHeight = container.Height();
loopInfo.colWidth = columnWidth;
loopInfo.rowHeight = rowHeight;
loopInfo.index = loopIndex;
int loopX = X();
int loopY = Y();
int x = (loopX > 0) ? loopX : 0;
int y = (loopY > 0) ? loopY : 0;
//set y position for vertical loop with valign bottom
if (orientation == eOrientation::vertical && vAlign == eAlign::bottom) {
int actRowheight = (rowHeight > 0) ? rowHeight : RowHeight();
if (actRowheight > 0) {
float fTotalItems = (float)loopHeight / (float)actRowheight;
int totalItems = (int)fTotalItems;
if (fTotalItems - (float)totalItems > 0.5f)
totalItems++;
if (maxItems > 0 && maxItems < totalItems)
totalItems = maxItems;
if (numRows < totalItems)
y += (totalItems - numRows) * actRowheight;
}
}
for (int row = 0; row < numRows; ++row) {
if (maxItems > 0 && row >= maxItems) {
break;
}
loopInfo.row = row;
//check overflow cut
if (overflow == eOverflowType::cut) {
if (orientation == eOrientation::horizontal && (row * columnWidth > loopWidth)) {
return;
} else if (orientation == eOrientation::vertical && (row * rowHeight > loopHeight)) {
return;
}
}
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
if (f->DoDebug())
f->Debug();
if (!f->DoExecute())
continue;
f->Render(p, x, y, columnWidth, rowHeight);
}
if (orientation == eOrientation::horizontal) {
if (columnWidth > 0) {
x += columnWidth;
} else {
x += ColumnWidth();
}
//check overflow wrap
if (overflow == eOverflowType::wrap && orientation == eOrientation::horizontal) {
if (x + columnWidth - 10 > loopWidth) {
x = X();
if (x < 0) x = 0;
y += rowHeight;
}
}
} else if (orientation == eOrientation::vertical) {
if (rowHeight > 0) {
y += rowHeight;
} else {
y += RowHeight();
}
}
}
}
int cFuncLoop::FuncWidth(void) {
loopInfo.row = 0;
int loopIndex = tokenContainer->LoopIndex(Name());
if (loopIndex < 0) {
esyslog("skindesigner: unknown loop function \"%s\"", Name());
return 0;
}
int numLoops = tokenContainer->NumLoops(loopIndex);
if (numLoops < 1)
return 0;
int columnWidth = GetValue((int)eLoopAttribs::columnwidth);
if (columnWidth <=0)
columnWidth = ColumnWidth();
eOverflowType overflow = (eOverflowType)GetValue((int)eLoopAttribs::overflow);
if (overflow == eOverflowType::cut) {
int maxItems = GetValue((int)eLoopAttribs::maxitems);
numLoops = std::min(numLoops, maxItems);
}
if (numLoops > 0)
return numLoops * columnWidth;
return 0;
}
int cFuncLoop::FuncHeight(void) {
loopInfo.row = 0;
int loopIndex = tokenContainer->LoopIndex(Name());
if (loopIndex < 0) {
esyslog("skindesigner: unknown loop function \"%s\"", Name());
return 0;
}
int numLoops = tokenContainer->NumLoops(loopIndex);
if (numLoops < 1)
return 0;
int rowHeight = GetValue((int)eLoopAttribs::rowheight);
if (rowHeight <=0)
rowHeight = RowHeight();
eOverflowType overflow = (eOverflowType)GetValue((int)eLoopAttribs::overflow);
if (overflow == eOverflowType::cut) {
int maxItems = GetValue((int)eLoopAttribs::maxitems);
numLoops = std::min(numLoops, maxItems);
} else if (overflow == eOverflowType::wrap) {
int loopWidth = Width();
if (loopWidth <= 0)
loopWidth = container.Width();
loopWidth++;
int columnWidth = GetValue((int)eLoopAttribs::columnwidth);
if (columnWidth <=0)
columnWidth = ColumnWidth();
int itemsPerRow = loopWidth / columnWidth;
int rows = numLoops / itemsPerRow;
if (numLoops % itemsPerRow > 0)
rows++;
return rows * rowHeight;
}
if (numLoops > 0)
return numLoops * rowHeight;
return 0;
}
void cFuncLoop::Debug(void) {
loopInfo.row = 0;
cFunction::Debug();
dsyslog("skindesigner: loopfunc Functions:");
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
f->Debug();
}
}
void cFuncLoop::SetAttributesDefs(void) {
attribIDs.insert(pair<string, int>("columnwidth", (int)eLoopAttribs::columnwidth));
attribIDs.insert(pair<string, int>("rowheight", (int)eLoopAttribs::rowheight));
attribIDs.insert(pair<string, int>("name", (int)eLoopAttribs::name));
attribIDs.insert(pair<string, int>("orientation", (int)eLoopAttribs::orientation));
attribIDs.insert(pair<string, int>("valign", (int)eLoopAttribs::valign));
attribIDs.insert(pair<string, int>("overflow", (int)eLoopAttribs::overflow));
attribIDs.insert(pair<string, int>("maxitems", (int)eLoopAttribs::maxitems));
attribNames.insert(pair<int, string>((int)eLoopAttribs::columnwidth, "columnwidth"));
attribNames.insert(pair<int, string>((int)eLoopAttribs::rowheight, "rowheight"));
attribNames.insert(pair<int, string>((int)eLoopAttribs::name, "name"));
attribNames.insert(pair<int, string>((int)eLoopAttribs::orientation, "orientation"));
attribNames.insert(pair<int, string>((int)eLoopAttribs::valign, "valign"));
attribNames.insert(pair<int, string>((int)eLoopAttribs::overflow, "overflow"));
attribNames.insert(pair<int, string>((int)eLoopAttribs::maxitems, "maxitems"));
}
int cFuncLoop::ColumnWidth(void) {
int width = 0;
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
if (!f->DoExecute())
continue;
int funcWidth = f->X() + f->FuncWidth();
if (funcWidth > width)
width = funcWidth;
}
return width;
}
int cFuncLoop::RowHeight(void) {
int height = 0;
for (cFunction *f = functions.First(); f; f = functions.Next(f)) {
if (!f->DoExecute())
continue;
int funcHeight = f->Y() + f->FuncHeight();
if (funcHeight > height)
height = funcHeight;
}
return height;
}
// --- cTextFloater ----------------------------------------------------------
cTextFloater::cTextFloater(void) {
text = eol = NULL;
lines = 0;
lastLine = -1;
}
cTextFloater::cTextFloater(const char *fext, const cFont *font, int width, int height, int floatWidth, int floatHeight, int maxLines) {
text = NULL;
Set(text, font, width, height, floatWidth, floatHeight, maxLines);
}
cTextFloater::~cTextFloater() {
free(text);
}
void cTextFloater::Set(const char *Text, const cFont *font, int width, int height, int floatWidth, int floatHeight, int maxLines) {
free(text);
text = Text ? strdup(Text) : NULL;
eol = NULL;
lines = 0;
lastLine = -1;
if (!text)
return;
lines = 1;
if (width <= 0)
return;
int lineHeight = font->Height();
bool cut = false;
if (height > 0)
cut = true;
bool doFloat = false;
if (floatWidth > 0 && floatHeight > 0)
doFloat = true;
int textWidth = width;
if (doFloat) {
textWidth = width - floatWidth;
}
char *Blank = NULL;
char *Delim = NULL;
int w = 0;
stripspace(text); // strips trailing newlines
for (char *p = text; *p; ) {
int sl = Utf8CharLen(p);
uint sym = Utf8CharGet(p, sl);
if (sym == '\n') {
if ((maxLines > 0) && (lines == maxLines)) {
while (*p) {
*p = 0;
p++;
}
return;
}
lines++;
if (cut) {
if (lines * lineHeight >= height) {
//remove last line, find last linebreak
p--;
int max = 100;
int i = 0;
while (*p) {
int sl = Utf8CharLen(p);
uint sym = Utf8CharGet(p, sl);
if (sym == '\n')
break;
p -= sl;
i++;
if (i > max)
break;
}
p++;
if (*p) {
*p = '.'; p++;
if (*p) {
*p = '.'; p++;
if (*p) {
*p = '.'; p++;
*p = 0;
}
}
}
break;
}
}
if (doFloat) {
if ((lines-1) * lineHeight >= floatHeight) {
textWidth = width;
}
}
w = 0;
Blank = Delim = NULL;
p++;
continue;
} else if (sl == 1 && isspace(sym))
Blank = p;
int cw = font->Width(sym);
if (w + cw > textWidth) {
if (Blank) {
*Blank = '\n';
p = Blank;
continue;
} else if (w > 0) { // there has to be at least one character before the newline
// Here's the ugly part, where we don't have any whitespace to
// punch in a newline, so we need to make room for it:
if (Delim)
p = Delim + 1; // let's fall back to the most recent delimiter
char *s = MALLOC(char, strlen(text) + 2); // The additional '\n' plus the terminating '\0'
int l = p - text;
strncpy(s, text, l);
s[l] = '\n';
strcpy(s + l + 1, p);
free(text);
text = s;
p = text + l;
continue;
}
}
w += cw;
if (strchr("-.,:;!?_", *p)) {
Delim = p;
Blank = NULL;
}
p += sl;
}
}
const char *cTextFloater::Text(void) {
if (eol) {
*eol = '\n';
eol = NULL;
}
return text;
}
const char *cTextFloater::GetLine(int line) {
char *s = NULL;
if (line < lines) {
if (eol) {
*eol = '\n';
if (line == lastLine + 1)
s = eol + 1;
eol = NULL;
}
if (!s) {
s = text;
for (int i = 0; i < line; i++) {
s = strchr(s, '\n');
if (s)
s++;
else
break;
}
}
if (s) {
if ((eol = strchr(s, '\n')) != NULL)
*eol = 0;
}
lastLine = line;
}
return s;
}