From 809fbda03c5014ba9cd361f5113d1d717cd41ea6 Mon Sep 17 00:00:00 2001 From: louis Date: Tue, 26 Jan 2016 18:32:38 +0100 Subject: Version 0.8.0 beta --- coreengine/functions.c | 1565 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1565 insertions(+) create mode 100644 coreengine/functions.c (limited to 'coreengine/functions.c') diff --git a/coreengine/functions.c b/coreengine/functions.c new file mode 100644 index 0000000..f8b8d47 --- /dev/null +++ b/coreengine/functions.c @@ -0,0 +1,1565 @@ +#define __STL_CONFIG_H +#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 &attributes) { + for (vector::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("color", (int)eFillAttribs::color)); + attribNames.insert(pair((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 &attributes) { + for (vector::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("align", (int)eDrawRectangleAttribs::align)); + attribIDs.insert(pair("valign", (int)eDrawRectangleAttribs::valign)); + attribIDs.insert(pair("color", (int)eDrawRectangleAttribs::color)); + attribIDs.insert(pair("name", (int)eDrawRectangleAttribs::name)); + attribIDs.insert(pair("animtype", (int)eDrawRectangleAttribs::animtype)); + attribIDs.insert(pair("animfreq", (int)eDrawRectangleAttribs::animfreq)); + attribNames.insert(pair((int)eDrawRectangleAttribs::align, "align")); + attribNames.insert(pair((int)eDrawRectangleAttribs::valign, "valign")); + attribNames.insert(pair((int)eDrawRectangleAttribs::color, "color")); + attribNames.insert(pair((int)eDrawRectangleAttribs::name, "name")); + attribNames.insert(pair((int)eDrawRectangleAttribs::animtype, "animtype")); + attribNames.insert(pair((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 &attributes) { + for (vector::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("align", (int)eDrawEllipseAttribs::align)); + attribIDs.insert(pair("valign", (int)eDrawEllipseAttribs::valign)); + attribIDs.insert(pair("color", (int)eDrawEllipseAttribs::color)); + attribIDs.insert(pair("name", (int)eDrawEllipseAttribs::name)); + attribIDs.insert(pair("quadrant", (int)eDrawEllipseAttribs::quadrant)); + attribIDs.insert(pair("animtype", (int)eDrawEllipseAttribs::animtype)); + attribIDs.insert(pair("animfreq", (int)eDrawEllipseAttribs::animfreq)); + attribNames.insert(pair((int)eDrawEllipseAttribs::align, "align")); + attribNames.insert(pair((int)eDrawEllipseAttribs::valign, "valign")); + attribNames.insert(pair((int)eDrawEllipseAttribs::color, "color")); + attribNames.insert(pair((int)eDrawEllipseAttribs::name, "name")); + attribNames.insert(pair((int)eDrawEllipseAttribs::quadrant, "quadrant")); + attribNames.insert(pair((int)eDrawEllipseAttribs::animtype, "animtype")); + attribNames.insert(pair((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 &attributes) { + for (vector::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("align", (int)eDrawSlopeAttribs::align)); + attribIDs.insert(pair("valign", (int)eDrawSlopeAttribs::valign)); + attribIDs.insert(pair("color", (int)eDrawSlopeAttribs::color)); + attribIDs.insert(pair("name", (int)eDrawSlopeAttribs::name)); + attribIDs.insert(pair("type", (int)eDrawSlopeAttribs::type)); + attribIDs.insert(pair("animtype", (int)eDrawSlopeAttribs::animtype)); + attribIDs.insert(pair("animfreq", (int)eDrawSlopeAttribs::animfreq)); + attribNames.insert(pair((int)eDrawSlopeAttribs::align, "align")); + attribNames.insert(pair((int)eDrawSlopeAttribs::valign, "valign")); + attribNames.insert(pair((int)eDrawSlopeAttribs::color, "color")); + attribNames.insert(pair((int)eDrawSlopeAttribs::name, "name")); + attribNames.insert(pair((int)eDrawSlopeAttribs::type, "type")); + attribNames.insert(pair((int)eDrawSlopeAttribs::animtype, "animtype")); + attribNames.insert(pair((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 &attributes) { + for (vector::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; + } + + 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; +} + +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("align", (int)eDrawTextAttribs::align)); + attribIDs.insert(pair("valign", (int)eDrawTextAttribs::valign)); + attribIDs.insert(pair("color", (int)eDrawTextAttribs::color)); + attribIDs.insert(pair("font", (int)eDrawTextAttribs::font)); + attribIDs.insert(pair("fontsize", (int)eDrawTextAttribs::fontsize)); + attribIDs.insert(pair("name", (int)eDrawTextAttribs::name)); + attribIDs.insert(pair("text", (int)eDrawTextAttribs::text)); + attribIDs.insert(pair("animtype", (int)eDrawTextAttribs::animtype)); + attribIDs.insert(pair("animfreq", (int)eDrawTextAttribs::animfreq)); + attribNames.insert(pair((int)eDrawTextAttribs::align, "align")); + attribNames.insert(pair((int)eDrawTextAttribs::valign, "valign")); + attribNames.insert(pair((int)eDrawTextAttribs::color, "color")); + attribNames.insert(pair((int)eDrawTextAttribs::font, "font")); + attribNames.insert(pair((int)eDrawTextAttribs::fontsize, "fontsize")); + attribNames.insert(pair((int)eDrawTextAttribs::name, "name")); + attribNames.insert(pair((int)eDrawTextAttribs::text, "text")); + attribNames.insert(pair((int)eDrawTextAttribs::animtype, "animtype")); + attribNames.insert(pair((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 &attributes) { + for (vector::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("align", (int)eDrawTextAttribsVertical::align)); + attribIDs.insert(pair("valign", (int)eDrawTextAttribsVertical::valign)); + attribIDs.insert(pair("direction", (int)eDrawTextAttribsVertical::direction)); + attribIDs.insert(pair("color", (int)eDrawTextAttribsVertical::color)); + attribIDs.insert(pair("font", (int)eDrawTextAttribsVertical::font)); + attribIDs.insert(pair("fontsize", (int)eDrawTextAttribsVertical::fontsize)); + attribIDs.insert(pair("name", (int)eDrawTextAttribsVertical::name)); + attribIDs.insert(pair("text", (int)eDrawTextAttribsVertical::text)); + attribIDs.insert(pair("animtype", (int)eDrawTextAttribsVertical::animtype)); + attribIDs.insert(pair("animfreq", (int)eDrawTextAttribsVertical::animfreq)); + attribNames.insert(pair((int)eDrawTextAttribsVertical::align, "align")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::valign, "valign")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::direction, "direction")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::color, "color")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::font, "font")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::fontsize, "fontsize")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::name, "name")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::text, "text")); + attribNames.insert(pair((int)eDrawTextAttribsVertical::animtype, "animtype")); + attribNames.insert(pair((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 &attributes) { + for (vector::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("align", (int)eDrawTextBoxAttribs::align)); + attribIDs.insert(pair("valign", (int)eDrawTextBoxAttribs::valign)); + attribIDs.insert(pair("maxlines", (int)eDrawTextBoxAttribs::maxlines)); + attribIDs.insert(pair("floatwidth", (int)eDrawTextBoxAttribs::floatwidth)); + attribIDs.insert(pair("floatheight", (int)eDrawTextBoxAttribs::floatheight)); + attribIDs.insert(pair("float", (int)eDrawTextBoxAttribs::floatmode)); + attribIDs.insert(pair("color", (int)eDrawTextBoxAttribs::color)); + attribIDs.insert(pair("font", (int)eDrawTextBoxAttribs::font)); + attribIDs.insert(pair("fontsize", (int)eDrawTextBoxAttribs::fontsize)); + attribIDs.insert(pair("name", (int)eDrawTextBoxAttribs::name)); + attribIDs.insert(pair("text", (int)eDrawTextBoxAttribs::text)); + attribNames.insert(pair((int)eDrawTextBoxAttribs::align, "align")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::valign, "valign")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::maxlines, "maxlines")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::floatwidth, "floatwidth")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::floatheight, "floatheight")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::floatmode, "float")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::color, "color")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::font, "font")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::fontsize, "fontsize")); + attribNames.insert(pair((int)eDrawTextBoxAttribs::name, "name")); + attribNames.insert(pair((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 &attributes) { + for (vector::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("align", (int)eDrawImageAttribs::align)); + attribIDs.insert(pair("valign", (int)eDrawImageAttribs::valign)); + attribIDs.insert(pair("imagetype", (int)eDrawImageAttribs::imagetype)); + attribIDs.insert(pair("name", (int)eDrawImageAttribs::name)); + attribIDs.insert(pair("cache", (int)eDrawImageAttribs::cache)); + attribIDs.insert(pair("path", (int)eDrawImageAttribs::path)); + attribIDs.insert(pair("animtype", (int)eDrawImageAttribs::animtype)); + attribIDs.insert(pair("animfreq", (int)eDrawImageAttribs::animfreq)); + attribNames.insert(pair((int)eDrawImageAttribs::align, "align")); + attribNames.insert(pair((int)eDrawImageAttribs::valign, "valign")); + attribNames.insert(pair((int)eDrawImageAttribs::imagetype, "imagetype")); + attribNames.insert(pair((int)eDrawImageAttribs::name, "name")); + attribNames.insert(pair((int)eDrawImageAttribs::cache, "cache")); + attribNames.insert(pair((int)eDrawImageAttribs::path, "path")); + attribNames.insert(pair((int)eDrawImageAttribs::animtype, "animtype")); + attribNames.insert(pair((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 &attributes) { + for (vector::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 { + 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); + 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); + 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; + 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); + 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 = 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); + 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 = 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("columnwidth", (int)eLoopAttribs::columnwidth)); + attribIDs.insert(pair("rowheight", (int)eLoopAttribs::rowheight)); + attribIDs.insert(pair("name", (int)eLoopAttribs::name)); + attribIDs.insert(pair("orientation", (int)eLoopAttribs::orientation)); + attribIDs.insert(pair("overflow", (int)eLoopAttribs::overflow)); + attribIDs.insert(pair("maxitems", (int)eLoopAttribs::maxitems)); + attribNames.insert(pair((int)eLoopAttribs::columnwidth, "columnwidth")); + attribNames.insert(pair((int)eLoopAttribs::rowheight, "rowheight")); + attribNames.insert(pair((int)eLoopAttribs::name, "name")); + attribNames.insert(pair((int)eLoopAttribs::orientation, "orientation")); + attribNames.insert(pair((int)eLoopAttribs::overflow, "overflow")); + attribNames.insert(pair((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; +} -- cgit v1.2.3