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