#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; } 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("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 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("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("valign", (int)eLoopAttribs::valign)); 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::valign, "valign")); 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; }