summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormrwastl <mrwastl@users.sourceforge.net>2010-05-15 11:30:17 +0200
committermrwastl <mrwastl@users.sourceforge.net>2010-05-15 11:30:17 +0200
commitb0cd921fe42210fc3a029c330b7a38a036b8dabc (patch)
treeefbdedff04d77013ed5dd5b7bd95783072904945
parenteccd044bc2179fb81a499433179e1f7c42a28800 (diff)
downloadgraphlcd-base-b0cd921fe42210fc3a029c330b7a38a036b8dabc.tar.gz
graphlcd-base-b0cd921fe42210fc3a029c330b7a38a036b8dabc.tar.bz2
glcdskin: added looping for images and scrolling for text-fields
-rw-r--r--glcdskin/display.c11
-rw-r--r--glcdskin/display.h2
-rw-r--r--glcdskin/object.c270
-rw-r--r--glcdskin/object.h25
-rw-r--r--glcdskin/parser.c4
5 files changed, 306 insertions, 6 deletions
diff --git a/glcdskin/display.c b/glcdskin/display.c
index b92fea5..a926bd9 100644
--- a/glcdskin/display.c
+++ b/glcdskin/display.c
@@ -28,6 +28,17 @@ void cSkinDisplay::Render(cBitmap * screen)
}
+bool cSkinDisplay::NeedsUpdate(uint64_t CurrentTime)
+{
+ for (uint32_t i = 0; i < NumObjects(); ++i) {
+ if ( GetObject(i)->NeedsUpdate(CurrentTime) ) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
cSkinDisplays::cSkinDisplays(void)
{
}
diff --git a/glcdskin/display.h b/glcdskin/display.h
index af50179..3b19b0c 100644
--- a/glcdskin/display.h
+++ b/glcdskin/display.h
@@ -43,6 +43,8 @@ public:
cSkinObject * GetObject(uint32_t n) const { return mObjects[n]; }
void Render(cBitmap * screen);
+
+ bool NeedsUpdate(uint64_t CurrentTime);
};
class cSkinDisplays: public std::vector<cSkinDisplay *>
diff --git a/glcdskin/object.c b/glcdskin/object.c
index c79fa59..5195806 100644
--- a/glcdskin/object.c
+++ b/glcdskin/object.c
@@ -3,6 +3,7 @@
#include "skin.h"
#include "cache.h"
#include "function.h"
+#include <sys/time.h>
namespace GLCD
{
@@ -43,6 +44,16 @@ cSkinObject::cSkinObject(cSkinDisplay * Parent)
mFont(this, false),
mText(this, false),
mCondition(NULL),
+ mLastChange(0),
+ mChangeDelay(-1), // delay between two images frames: -1: not animated / don't care
+ mStoredImagePath(""),
+ mImageFrameId(0), // start with 1st frame
+ mScrollLoopMode(-1), // scroll (text) or loop (image) mode: default (-1)
+ mScrollLoopReached(false), // if scroll/loop == once: already looped once?
+ mScrollSpeed(0), // scroll speed: default (0)
+ mScrollTime(0), // scroll time interval: default (0)
+ mScrollOffset(0), // scroll offset (pixels)
+ mCurrText(""),
mObjects(NULL)
{
}
@@ -66,6 +77,16 @@ cSkinObject::cSkinObject(const cSkinObject & Src)
mFont(Src.mFont),
mText(Src.mText),
mCondition(Src.mCondition),
+ mLastChange(0),
+ mChangeDelay(-1),
+ mStoredImagePath(""),
+ mImageFrameId(0),
+ mScrollLoopMode(Src.mScrollLoopMode),
+ mScrollLoopReached(Src.mScrollLoopReached),
+ mScrollSpeed(Src.mScrollSpeed),
+ mScrollTime(Src.mScrollTime),
+ mScrollOffset(Src.mScrollOffset),
+ mCurrText(Src.mCurrText),
mObjects(NULL)
{
if (Src.mObjects)
@@ -181,6 +202,50 @@ bool cSkinObject::ParseFontFace(const std::string & Text)
return mFont.Parse(Text);
}
+
+bool cSkinObject::ParseScrollLoopMode(const std::string & Text)
+{
+ if (Text == "never")
+ mScrollLoopMode = 0;
+ else if (Text == "once")
+ mScrollLoopMode = 1;
+ else if (Text == "always")
+ mScrollLoopMode = 2;
+ else
+ return false;
+ return true;
+}
+
+bool cSkinObject::ParseScrollSpeed(const std::string & Text)
+{
+ int val;
+ if (!ParseIntParam(Text, val))
+ return false;
+
+ if (val < 0 || val > 10)
+ return false;
+
+ mScrollSpeed = val;
+ return true;
+}
+
+bool cSkinObject::ParseScrollTime(const std::string & Text)
+{
+ int val;
+ if (!ParseIntParam(Text, val))
+ return false;
+
+ if (val < 0 || val > 2000)
+ return false;
+
+ if (val > 0 && val < 100)
+ val = 100;
+
+ mScrollTime = val;
+ return true;
+}
+
+
void cSkinObject::SetListIndex(int MaxItems, int Index)
{
mText.SetListIndex(MaxItems, Index);
@@ -211,22 +276,63 @@ tSize cSkinObject::Size(void) const
void cSkinObject::Render(GLCD::cBitmap * screen)
{
+ struct timeval tv;
+ uint64_t timestamp;
+
if (mCondition != NULL && !mCondition->Evaluate())
return;
+ gettimeofday(&tv, 0);
+ timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
switch (Type())
{
case cSkinObject::image:
{
cImageCache * cache = mSkin->ImageCache();
- GLCD::cImage * image = cache->Get(mPath.Evaluate());
+ int currScrollLoopMode = 2; //default if not configured in the skin: always
+
+ cType evalPath = mPath.Evaluate();
+ std::string currPath = evalPath;
+
+ if (currPath != mStoredImagePath) {
+ mImageFrameId = 0;
+ mStoredImagePath = currPath;
+ mScrollLoopReached = false;
+ mLastChange = timestamp;
+ }
+
+ GLCD::cImage * image = cache->Get(evalPath);
if (image)
{
- const GLCD::cBitmap * bitmap = image->GetBitmap();
+ int framecount = image->Count();
+
+ const GLCD::cBitmap * bitmap = image->GetBitmap(mImageFrameId);
+
if (bitmap)
{
screen->DrawBitmap(Pos().x, Pos().y, *bitmap, mColor);
}
+
+ if (mScrollLoopMode != -1) // if == -1: currScrollLoopMode already contains correct value
+ currScrollLoopMode = mScrollLoopMode;
+
+ mChangeDelay = image->Delay();
+ if (mChangeDelay != -1 && currScrollLoopMode > 0 && !mScrollLoopReached && framecount > 1) {
+
+ if ( (int)(timestamp - mLastChange) >= mChangeDelay) {
+
+ if (currScrollLoopMode == 1 && mImageFrameId+1 == framecount) {
+ mScrollLoopReached = true; // stop looping and switch to 1st frame
+ }
+
+ mImageFrameId = (mImageFrameId+1) % framecount;
+ mLastChange = timestamp;
+ }
+ }
+
+ if (mLastChange == 0)
+ mLastChange = timestamp;
}
break;
}
@@ -301,14 +407,49 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
}
case cSkinObject::text:
+ case cSkinObject::scrolltext:
{
cSkinFont * skinFont = mSkin->GetFont(mFont.Evaluate());
+ int currScrollLoopMode = 1; // default values if no setup default values available
+ int currScrollSpeed = 8;
+ int currScrollTime = 500;
+
+ // get default values from derived config-class if available
+ tSkinToken token = tSkinToken();
+ token.Id = mSkin->Config().GetTokenId("ScrollMode");
+ if (token.Id >= 0) {
+ cType t = mSkin->Config().GetToken(token);
+ currScrollLoopMode = (int)(t);
+ }
+ token.Id = mSkin->Config().GetTokenId("ScrollSpeed");
+ if (token.Id >= 0) {
+ cType t = mSkin->Config().GetToken(token);
+ currScrollSpeed = (int)(t);
+ }
+ token.Id = mSkin->Config().GetTokenId("ScrollTime");
+ if (token.Id >= 0) {
+ cType t = mSkin->Config().GetToken(token);
+ currScrollTime = (int)(t);
+ }
+
if (skinFont)
{
const cFont * font = skinFont->Font();
std::string text = mText.Evaluate();
+
+ if (! (text == mCurrText) ) {
+ mScrollOffset = 0;
+ mCurrText = text;
+ mScrollLoopReached = false;
+ mLastChange = timestamp;
+ }
+
if (mMultiline)
{
+
+ // scrolling in multiline not supported at the moment
+ mScrollLoopReached = true; // avoid check in NeedsUpdate()
+
std::vector <std::string> lines;
font->WrapText(Size().w, Size().h, text, lines);
for (size_t i = 0; i < lines.size(); i++)
@@ -334,6 +475,9 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
if (text.find('\t') != std::string::npos
&& mSkin->Config().GetTabPosition(0, Size().w, *font) > 0)
{
+ // scrolling in texts with tabulators not supported at the moment
+ mScrollLoopReached = true; // avoid check in NeedsUpdate()
+
std::string::size_type pos1;
std::string::size_type pos2;
std::string str;
@@ -363,8 +507,12 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
{
int w = font->Width(text);
int x = Pos().x;
+ bool updateScroll = false;
+
if (w < Size().w)
{
+ mScrollLoopReached = true; // avoid check in NeedsUpdate()
+
if (mAlign == taRight)
{
x += Size().w - w;
@@ -373,18 +521,53 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
{
x += (Size().w - w) / 2;
}
+ } else {
+
+ if (mScrollLoopMode != -1) // if == -1: currScrollLoopMode already contains correct value
+ currScrollLoopMode = mScrollLoopMode;
+
+ if (mScrollSpeed > 0)
+ currScrollSpeed = mScrollSpeed;
+
+ if (mScrollTime > 0)
+ currScrollTime = mScrollTime;
+
+ if (currScrollLoopMode > 0 && (!mScrollLoopReached || mScrollOffset) &&
+ ((int)(timestamp-mLastChange) >= currScrollTime)
+ )
+ {
+ if (mScrollLoopReached)
+ mScrollOffset = 0;
+ else
+ updateScroll = true;
+ }
+
+ }
+ screen->DrawText(x, Pos().y, x + Size().w - 1, text, font, mColor, true, mScrollOffset);
+
+ if (updateScroll) {
+ mScrollOffset += currScrollSpeed;
+
+ if ( x + Size().w + mScrollOffset > w+Size().w) {
+ if (currScrollLoopMode == 1)
+ // reset mScrollOffset in next step (else: string not redrawn when scroll done)
+ mScrollLoopReached = true;
+ else
+ mScrollOffset= 0;
+ }
+ updateScroll = false;
+ mLastChange = timestamp;
}
- screen->DrawText(x, Pos().y, x + Size().w - 1, text, font, mColor);
}
}
}
break;
}
- case cSkinObject::scrolltext:
+// case cSkinObject::scrolltext:
//DrawScrolltext(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(),
// Object->Align());
- break;
+// break;
case cSkinObject::scrollbar:
//DrawScrollbar(Object->Pos(), Object->Size(), Object->Bg(), Object->Fg());
@@ -430,6 +613,83 @@ void cSkinObject::Render(GLCD::cBitmap * screen)
}
}
+bool cSkinObject::NeedsUpdate(uint64_t CurrentTime)
+{
+ if (mCondition != NULL && !mCondition->Evaluate())
+ return false;
+
+ switch (Type())
+ {
+ case cSkinObject::image:
+ {
+ int currScrollLoopMode = 2;
+
+ if (mScrollLoopMode != -1)
+ currScrollLoopMode = mScrollLoopMode;
+
+ if ( mChangeDelay > 0 && currScrollLoopMode > 0 && !mScrollLoopReached &&
+ ( (int)(CurrentTime-mLastChange) >= mChangeDelay)
+ )
+ {
+ return true;
+ }
+ return false;
+ break;
+ }
+ case cSkinObject::text:
+ case cSkinObject::scrolltext:
+ {
+ int currScrollLoopMode = 1; // default values if no setup default values available
+ int currScrollTime = 500;
+
+ // get default values from derived config-class if available
+ tSkinToken token = tSkinToken();
+ token.Id = mSkin->Config().GetTokenId("ScrollMode");
+ if (token.Id >= 0) {
+ cType t = mSkin->Config().GetToken(token);
+ currScrollLoopMode = (int)(t);
+ }
+ token.Id = mSkin->Config().GetTokenId("ScrollTime");
+ if (token.Id >= 0) {
+ cType t = mSkin->Config().GetToken(token);
+ currScrollTime = (int)(t);
+ }
+
+ if (mScrollLoopMode != -1) // if == -1: currScrollLoopMode already contains correct value
+ currScrollLoopMode = mScrollLoopMode;
+
+ if (mScrollTime > 0)
+ currScrollTime = mScrollTime;
+
+ if (currScrollLoopMode > 0 && (!mScrollLoopReached || mScrollOffset) &&
+ (int)(CurrentTime-mLastChange) >= currScrollTime
+ )
+ {
+ return true;
+ }
+ return false;
+ break;
+ }
+ case cSkinObject::progress:
+ return false;
+ break;
+ case cSkinObject::block:
+ {
+ for (uint32_t i = 0; i < NumObjects(); i++) {
+ if ( GetObject(i)->NeedsUpdate(CurrentTime) ) {
+ return true;
+ }
+ }
+ return false;
+ break;
+ }
+ default: // all other elements are static ones
+ return false;
+ }
+ return false;
+}
+
+
cSkinObjects::cSkinObjects(void)
{
}
diff --git a/glcdskin/object.h b/glcdskin/object.h
index f164747..188dd79 100644
--- a/glcdskin/object.h
+++ b/glcdskin/object.h
@@ -96,6 +96,21 @@ private:
cSkinString mText;
cSkinFunction * mCondition;
+ uint64_t mLastChange; // last change in dynamic object (scroll, frame change, ...)
+ int mChangeDelay; // delay between two changes (frame change, scrolling, ...)
+ // special values: -2: no further looping (mScrollLoopMode == 'once')
+ // -1: not set (ie: not an animated image)
+
+ std::string mStoredImagePath; // stored image path
+ int mImageFrameId; // frame ID of image
+
+ int mScrollLoopMode; // scroll (text) or loop (image) mode: -1: default, 0: never, 1: once, 2: always
+ bool mScrollLoopReached; // if scroll/loop == once: already looped once?
+ int mScrollSpeed; // scroll speed: 0: default, [1 - 10]: speed
+ int mScrollTime; // scroll time interval: 0: default, [100 - 2000]: time interval
+ int mScrollOffset; // scroll offset (pixels)
+ std::string mCurrText; // current text (for checks if text has changed)
+
cSkinObjects * mObjects; // used for block objects such as <list>
public:
@@ -112,11 +127,15 @@ public:
bool ParseWidth(const std::string &Text);
bool ParseHeight(const std::string &Text);
+ bool ParseScrollLoopMode(const std::string & Text);
+ bool ParseScrollSpeed(const std::string & Text);
+ bool ParseScrollTime(const std::string & Text);
+
void SetListIndex(int MaxItems, int Index);
eType Type(void) const { return mType; }
cSkinFunction * Condition(void) const { return mCondition; }
- cSkinDisplay * Display(void) const { return mDisplay; }
+ cSkinDisplay * Display(void) const { return mDisplay; }
cSkin * Skin(void) const { return mSkin; }
const std::string & TypeName(void) const;
@@ -127,6 +146,10 @@ public:
cSkinObject * GetObject(uint32_t Index) const;
void Render(cBitmap * screen);
+
+ // check if update is required for dynamic objects (image, text, progress, pane)
+ // false: no update required, true: update required
+ bool NeedsUpdate(uint64_t CurrentTime);
};
class cSkinObjects: public std::vector<cSkinObject *>
diff --git a/glcdskin/parser.c b/glcdskin/parser.c
index d20988f..cd76b24 100644
--- a/glcdskin/parser.c
+++ b/glcdskin/parser.c
@@ -205,6 +205,7 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att
ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos2.y);
ATTRIB_OPT_FUNC("color", object->ParseColor);
ATTRIB_MAN_FUNC("path", object->mPath.Parse);
+ ATTRIB_OPT_FUNC("loop", object->ParseScrollLoopMode);
}
else if (name == "text"
|| name == "scrolltext")
@@ -213,6 +214,9 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att
ATTRIB_OPT_FUNC("align", object->ParseAlignment);
ATTRIB_OPT_FUNC("font", object->ParseFontFace);
ATTRIB_OPT_BOOL("multiline", object->mMultiline);
+ ATTRIB_OPT_FUNC("scrollmode", object->ParseScrollLoopMode);
+ ATTRIB_OPT_FUNC("scrollspeed", object->ParseScrollSpeed);
+ ATTRIB_OPT_FUNC("scrolltime", object->ParseScrollTime);
#if 0
if (name == "blink")
{