From 0b3f86344a87940d324695e0bc9449c35cbf60d4 Mon Sep 17 00:00:00 2001 From: Christian Tusche Date: Sun, 6 May 2007 17:26:51 +0200 Subject: 2007-05-06: Version 1.1-cvs_ext-0.10a (text2skin-1.1-cvs_ext-0.10a.diff) - increased efficiency in drawing list items in the main menu - introduce relative Pos and Size of objects to given BasePos, BaseSize (used to draw list items) --- HISTORY | 6 ++ Makefile | 2 +- display.c | 101 +++++++++++------- render.c | 335 ++++++++++++++++++++++++++++++++++------------------------ render.h | 11 +- xml/display.h | 2 +- xml/object.c | 23 ++-- xml/object.h | 10 +- 8 files changed, 297 insertions(+), 193 deletions(-) diff --git a/HISTORY b/HISTORY index 90fbcfe..20142fe 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,12 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- +2007-05-06: Version 1.1-cvs_ext-0.10a (text2skin-1.1-cvs_ext-0.10a.diff) + +- increased efficiency in drawing list items in the main menu +- introduce relative Pos and Size of objects to given BasePos, BaseSize + (used to draw list items) + 2006-12-03: Version 1.1-cvs_ext-0.10 (vdr-text2skin-1.1-cvs_ext-0.10.diff) - set EditableWidth. This is important for plugins like 'rotor' or diff --git a/Makefile b/Makefile index 4591578..625d43e 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ ifdef DEBUG CXXFLAGS += -g -fno-inline DEFINES += -DDEBUG else - CXXFLAGS += -O2 -g + CXXFLAGS += -O3 ifdef BENCH DEFINES += -DBENCH endif diff --git a/display.c b/display.c index 9960eac..8c03c12 100644 --- a/display.c +++ b/display.c @@ -962,11 +962,8 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) switch (Token.Type) { case tMenuItem: case tMenuGroup: - if (Token.Index < 0) return false; case tMenuCurrent: - if (Token.Index >= 0 && Token.Tab == -1) return false; break; - default: if (Token.Tab >= 0) return false; break; @@ -977,38 +974,63 @@ cxType cText2SkinDisplayMenu::GetTokenData(const txToken &Token) return mTitle; case tMenuItem: - return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel - && mCurrentItem != (uint)Token.Index - ? (cxType)mItems[Token.Index].tabs[Token.Tab] - : (cxType)false; + if (Token.Index < 0) return false; + + if( mItems.size() <= (uint)Token.Index || !mItems[Token.Index].sel || + mCurrentItem == (uint)Token.Index ) + return false; + + if (Token.Tab < 0) { + return Token.Attrib.Type == aNumber + ? (cxType)mItems[Token.Index].tabs[Token.Attrib.Number] + : (cxType)mItems[Token.Index].text; + } + + return (cxType)mItems[Token.Index].tabs[Token.Tab]; case tIsMenuItem: return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel && mCurrentItem != (uint)Token.Index; case tMenuCurrent: + if(mItems.size() <= mCurrentItem) + return false; + if (Token.Index < 0) { - if (mItems.size() > mCurrentItem) - return Token.Attrib.Type == aNumber - ? (cxType)mItems[mCurrentItem].tabs[Token.Attrib.Number] - : (cxType)mItems[mCurrentItem].text; - else - return false; + return Token.Attrib.Type == aNumber + ? (cxType)mItems[mCurrentItem].tabs[Token.Attrib.Number] + : (cxType)mItems[mCurrentItem].text; } - return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel - && mCurrentItem == (uint)Token.Index - ? (cxType)mItems[Token.Index].tabs[Token.Tab] - : (cxType)false; + if( mItems.size() <= (uint)Token.Index || !mItems[Token.Index].sel || + mCurrentItem != (uint)Token.Index ) + return false; + + if (Token.Tab < 0) { + return Token.Attrib.Type == aNumber + ? (cxType)mItems[Token.Index].tabs[Token.Attrib.Number] + : (cxType)mItems[Token.Index].text; + } + + return (cxType)mItems[Token.Index].tabs[Token.Tab]; case tIsMenuCurrent: return mItems.size() > (uint)Token.Index && mItems[Token.Index].sel && mCurrentItem == (uint)Token.Index; case tMenuGroup: - return mItems.size() > (uint)Token.Index && !mItems[Token.Index].sel - ? (cxType)mItems[Token.Index].tabs[Token.Tab] - : (cxType)false; + if (Token.Index < 0) return false; + + if( mItems.size() <= (uint)Token.Index || mItems[Token.Index].sel) + return false; + + if (Token.Tab < 0) { + return Token.Attrib.Type == aNumber + ? (cxType)mItems[Token.Index].tabs[Token.Attrib.Number] + : (cxType)mItems[Token.Index].text; + } + + return (cxType)mItems[Token.Index].tabs[Token.Tab]; case tIsMenuGroup: return mItems.size() > (uint)Token.Index && !mItems[Token.Index].sel; @@ -1417,17 +1439,7 @@ void cText2SkinDisplayTracks::SetAudioChannel(int AudioChannel) cxType cText2SkinDisplayTracks::GetTokenData(const txToken &Token) { - switch (Token.Type) { - case tMenuItem: - if (Token.Index < 0) return false; - case tMenuCurrent: - if (Token.Index >= 0 && Token.Tab == -1) return false; - break; - - default: - if (Token.Tab >= 0) return false; - break; - } + if (Token.Tab >= 0) return false; int index = Token.Index; if (index >= 0 && mCurrentItem >= (uint)mMaxItems) { @@ -1440,17 +1452,28 @@ cxType cText2SkinDisplayTracks::GetTokenData(const txToken &Token) return mTitle; case tMenuItem: - return mItems.size() > (uint)index && mCurrentItem != (uint)index - ? (cxType)mItems[index] - : (cxType)false; - + if (index < 0) return false; + + if( mItems.size() <= (uint)index || mCurrentItem == (uint)index ) + return false; + + return (cxType)mItems[index]; + case tIsMenuItem: return mItems.size() > (uint)index && mCurrentItem != (uint)index; - + case tMenuCurrent: - return mItems.size() > (uint)index && mCurrentItem == (uint)index - ? (cxType)mItems[index] - : (cxType)false; + if(mItems.size() <= mCurrentItem) + return false; + + if (index < 0) { + return (cxType)mItems[mCurrentItem]; + } + + if( mItems.size() <= (uint)index || mCurrentItem != (uint)index ) + return false; + + return (cxType)mItems[index]; case tIsMenuCurrent: return mItems.size() > (uint)index && mCurrentItem == (uint)index; diff --git a/render.c b/render.c index 87df8a3..b300f9e 100644 --- a/render.c +++ b/render.c @@ -37,7 +37,9 @@ cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, cxDisplay::eType Di mStarted(), mUpdateIn(0), mNow(0), - mBaseSize() + mBaseSize(), + mTabScale(1.0), + mTabScaleSet(false) { if (mDisplay == NULL) { esyslog("ERROR: text2skin: display for %s missing", cxDisplay::GetType(Display).c_str()); @@ -163,188 +165,113 @@ void cText2SkinRender::Update(void) //printf("====\t%d\n", mDisplay->Objects()); } -void cText2SkinRender::DrawObject(const cxObject *Object) +void cText2SkinRender::DrawObject( cxObject *Object, + const txPoint &BaseOffset /*=txPoint(-1,-1)*/, + const txSize &BaseSize /*=txPoint(-1,-1)*/, + int ListItem /*=-1*/ ) { if (Object->Condition() != NULL && !Object->Condition()->Evaluate()) return; + txPoint pos; + txSize size; + + pos = Object->Pos(BaseOffset, BaseSize); + + size = Object->Size(BaseOffset, BaseSize); + + switch (Object->Type()) { case cxObject::image: - DrawImage(Object->Pos(), Object->Size(), Object->Bg(), Object->Fg(), Object->Mask(), + DrawImage(pos, size, Object->Bg(), Object->Fg(), Object->Mask(), Object->Alpha(), Object->Colors(), Object->Path()); break; case cxObject::text: - DrawText(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(), - Object->Align()); + if( ListItem >= 0 && Object->Display()->Type() == cxDisplay::menu ) + DrawItemText( Object, ListItem, pos, BaseSize ); + else + DrawText(pos, size, Object->Fg(), Object->Text(), Object->Font(), + Object->Align()); break; case cxObject::marquee: - DrawMarquee(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(), - Object->Align(), Object->Delay(), Object->Index()); + if( ListItem >= 0 && Object->Display()->Type() == cxDisplay::menu ) + DrawItemText( Object, ListItem, pos, BaseSize ); + else + DrawMarquee(pos, size, Object->Fg(), Object->Text(), Object->Font(), + Object->Align(), Object->Delay(), Object->Index()); break; case cxObject::blink: - DrawBlink(Object->Pos(), Object->Size(), Object->Fg(), Object->Bg(), Object->Text(), - Object->Font(), Object->Align(), Object->Delay(), Object->Index()); + if( ListItem >= 0 && Object->Display()->Type() == cxDisplay::menu ) + DrawItemText( Object, ListItem, pos, BaseSize ); + else + DrawBlink(pos, size, Object->Fg(), Object->Bg(), Object->Text(), + Object->Font(), Object->Align(), Object->Delay(), + Object->Index()); break; case cxObject::rectangle: - DrawRectangle(Object->Pos(), Object->Size(), Object->Fg()); + DrawRectangle(pos, size, Object->Fg()); break; case cxObject::ellipse: - DrawEllipse(Object->Pos(), Object->Size(), Object->Fg(), Object->Arc()); + DrawEllipse(pos, size, Object->Fg(), Object->Arc()); break; case cxObject::slope: - DrawSlope(Object->Pos(), Object->Size(), Object->Fg(), Object->Arc()); + DrawSlope(pos, size, Object->Fg(), Object->Arc()); break; case cxObject::progress: - DrawProgressbar(Object->Pos(), Object->Size(), Object->Current(), Object->Total(), + DrawProgressbar(pos, size, Object->Current(), Object->Total(), Object->Bg(), Object->Fg(), Object->Keep(), Object->Mark(), Object->Active(), GetMarks()); break; case cxObject::scrolltext: - DrawScrolltext(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(), + DrawScrolltext(pos, size, Object->Fg(), Object->Text(), Object->Font(), Object->Align()); break; case cxObject::scrollbar: - DrawScrollbar(Object->Pos(), Object->Size(), Object->Bg(), Object->Fg()); + DrawScrollbar(pos, size, Object->Bg(), Object->Fg()); case cxObject::block: for (uint i = 0; i < Object->Objects(); ++i) - DrawObject(Object->GetObject(i)); + DrawObject(Object->GetObject(i), pos, size, ListItem ); break; - case cxObject::list: { - const cxObject *item = Object->GetObject(0); - if (item && item->Type() == cxObject::item) { - txSize areasize = Object->Size(); - uint itemheight = item->Size().h; - uint maxitems = areasize.h / itemheight; - uint yoffset = 0; - bool initialEditableWidthSet = false; - - mMenuScrollbar.maxItems = maxitems; - SetMaxItems(maxitems); //Dprintf("setmaxitems %d\n", maxitems); - for (uint i = 0; i < maxitems; ++i, yoffset += itemheight) { - for (uint j = 1; j < Object->Objects(); ++j) { - const cxObject *o = Object->GetObject(j); - int maxtabs = 1; - - if (o->Display()->Type() == cxDisplay::menu) - maxtabs = cSkinDisplayMenu::MaxTabs; - - for (int t = -1; t < maxtabs; ++t) { - if (!HasTabText(i, t)) - continue; - - int thistab = GetTab(t); - int nexttab = GetTab(t + 1); - - cxObject obj(*o); - obj.SetListIndex(i, t); - if (obj.Condition() != NULL && !obj.Condition()->Evaluate()) - continue; - - obj.mPos1.x += Object->mPos1.x + (t >= 0 ? thistab : 0); - obj.mPos1.y += Object->mPos1.y + yoffset; - - // get end position - if (t >= 0 && nexttab > 0) { - // there is a "next tab".. see if it contains text - int n = t + 1; - while (n < cSkinDisplayMenu::MaxTabs && !HasTabText(i, n)) - ++n; - nexttab = GetTab(n); - } - - // set initial EditableWidth - // this is for plugins like 'extrecmenu' and 'rotor' - if ((obj.Type() == cxObject::text || obj.Type() == cxObject::marquee || obj.Type() == cxObject::blink) && !initialEditableWidthSet) { - initialEditableWidthSet = true; - SetEditableWidth(obj.Size().w); - } - - if (t >= 0 && nexttab > 0 && nexttab < obj.mPos1.x + obj.Size().w - 1) - // there is a "next tab" with text - obj.mPos2.x = Object->mPos1.x + o->mPos1.x + nexttab; - else { - // there is no "next tab", use the rightmost edge - obj.mPos2.x += Object->mPos1.x; - /* not used anymore due to change to fontOsd - but could be usefull if someone uses a differnt font - - if ((obj.Type() == cxObject::text || obj.Type() == cxObject::marquee || obj.Type() == cxObject::blink) && t == 1) { - // VDR assumes, that the font in the menu is fontOsd, - // so the EditableWidth is not necessarily correct - // for TTF - const cFont *defFont = cFont::GetFont(fontOsd); - const char *dummy = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "; - int editableWidth = obj.Size().w; - if (defFont != obj.Font()) - editableWidth = (int)(editableWidth * defFont->Width(dummy) / (1.1 * obj.Font()->Width(dummy))); - SetEditableWidth(editableWidth); - } */ - if ((obj.Type() == cxObject::text || obj.Type() == cxObject::marquee || obj.Type() == cxObject::blink) && t == 1) - SetEditableWidth(obj.Size().w); - } - - obj.mPos2.y += Object->mPos1.y + yoffset; - - std::string text = obj.Text(); - bool isprogress = false; - if (text.length() > 5 - && text[0] == '[' && text[text.length() - 1] == ']') { - const char *p = text.c_str() + 1; - isprogress = true; - for (; *p != ']'; ++p) { - if (*p != ' ' && *p != '|') { - isprogress = false; - break; - } - } - } - - if (isprogress) { - //Dprintf("detected progress bar tab\n"); - if (obj.Condition() == NULL || obj.Condition()->Evaluate()) { - int total = text.length() - 2; - int current = 0; - const char *p = text.c_str() + 1; - while (*p == '|') - (++current, ++p); - - txPoint pos = obj.Pos(); - txSize size = obj.Size(); - - DrawRectangle(txPoint(pos.x, pos.y + 4), - txSize(size.w, 2), obj.Fg()); - DrawRectangle(txPoint(pos.x, pos.y + 4), - txSize(2, size.h - 8), obj.Fg()); - DrawRectangle(txPoint(pos.x, pos.y + size.h - 6), - txSize(size.w, 2), obj.Fg()); - DrawRectangle(txPoint(pos.x + size.w - 2, pos.y + 4), - txSize(2, size.h - 8), obj.Fg()); - - pos.x += 4; - pos.y += 8; - size.w -= 8; - size.h -= 16; - DrawProgressbar(pos, size, current, total, obj.Bg(), - obj.Fg(), NULL, NULL, NULL, NULL); - } - } else - DrawObject(&obj); - } - } + case cxObject::list:{ + cxObject *item = Object->GetObject(0); + if (item && item->Type() == cxObject::item) { + txSize itemsize = item->Size(pos, size); + txPoint itempos = pos; + itemsize.w = size.w; + uint maxitems = size.h / itemsize.h; + mMenuScrollbar.maxItems = maxitems; + SetMaxItems(maxitems); //Dprintf("setmaxitems %d\n", maxitems); + uint index = 0; + + // draw list items + for (uint i = 0; i < maxitems; ++i) { + if (!HasTabText(i, -1)) + continue; + + Dbench(item); + index = i; + + itempos.y = pos.y + index * itemsize.h; + for (uint j = 1; j < Object->Objects(); ++j) { + item = Object->GetObject(j); + item->SetListIndex( index, -1 ); + DrawObject( item, itempos, itemsize, index ); } + Ddiff( "draw item", item ); } } + } break; case cxObject::item: @@ -354,6 +281,138 @@ void cText2SkinRender::DrawObject(const cxObject *Object) } } + + + + + + + +void cText2SkinRender::DrawItemText(cxObject *Object, int i, const txPoint &ListOffset, const txSize &ListSize) +{ + bool initialEditableWidthSet = false; + int maxtabs = cSkinDisplayMenu::MaxTabs; + txPoint Pos = ListOffset; + txSize BaseSize = Object->Size(ListOffset, ListSize); + txSize Size = BaseSize; + + if( !mTabScaleSet ) { + // VDR assumes, that the font in the menu is fontOsd, + // so the tab width is not necessarily correct + // for TTF + const cFont *defFont = cFont::GetFont(fontOsd); + const char *dummy = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "; + if( defFont != Object->Font() ) + mTabScale = 1.05 * (float)Object->Font()->Width(dummy) / (float)defFont->Width(dummy); + mTabScaleSet = true; + } + + // loop over tabs + for (int t = 0; t < maxtabs; ++t) { + if (!HasTabText(i, t)) + continue; + + int thistab = (int)(mTabScale * GetTab(t)); + int nexttab = (int)(mTabScale * GetTab(t + 1)); + + Object->SetListIndex(i, t); + //if (Object.Condition() != NULL && !Object.Condition()->Evaluate()) + // continue; + + // set initial EditableWidth + // this is for plugins like 'extrecmenu' and 'rotor' + if ( !initialEditableWidthSet ) { + initialEditableWidthSet = true; + SetEditableWidth((int)(Size.w / mTabScale)); + } + + // Start position of the tab + Pos.x = ListOffset.x + (t >= 0 ? thistab : 0); + + // get end position + if (t >= 0 && nexttab > 0) { + // there is a "next tab".. see if it contains text + int n = t + 1; + while (n < cSkinDisplayMenu::MaxTabs && !HasTabText(i, n)) + ++n; + nexttab = (int)(mTabScale * GetTab(n)); + } + + if (t >= 0 && nexttab > 0 && nexttab < BaseSize.w - 1) + // there is a "next tab" with text + Size.w = nexttab - thistab; + else { + // there is no "next tab", use the rightmost edge + Size.w = BaseSize.w - thistab; + if ( t == 1) + SetEditableWidth((int)(Size.w / mTabScale)); + } + + // Does the current tab contain a text-progress bar? + std::string text = Object->Text(); + bool isprogress = false; + if (text.length() > 5 && text[0] == '[' && text[text.length() - 1] == ']') { + const char *p = text.c_str() + 1; + isprogress = true; + for (; *p != ']'; ++p) { + if (*p != ' ' && *p != '|') { + isprogress = false; + break; + } + } + } + + if (isprogress) { + //Dprintf("detected progress bar tab\n"); + int total = text.length() - 2; + int current = 0; + const char *p = text.c_str() + 1; + while (*p == '|') + (++current, ++p); + + txPoint prog_pos = Pos; + txSize prog_size = Size; + + DrawRectangle(txPoint(prog_pos.x, prog_pos.y + 4), + txSize(prog_size.w, 2), Object->Fg()); + DrawRectangle(txPoint(prog_pos.x, prog_pos.y + 4), + txSize(2, prog_size.h - 8), Object->Fg()); + DrawRectangle(txPoint(prog_pos.x, prog_pos.y + prog_size.h - 6), + txSize(prog_size.w, 2), Object->Fg()); + DrawRectangle(txPoint(prog_pos.x + prog_size.w - 2, prog_pos.y + 4), + txSize(2, prog_size.h - 8), Object->Fg()); + + prog_pos.x += 4; + prog_pos.y += 8; + prog_size.w -= 8; + prog_size.h -= 16; + DrawProgressbar(prog_pos, prog_size, current, total, Object->Bg(), + Object->Fg(), NULL, NULL, NULL, NULL); + } else { + switch (Object->Type()) { + case cxObject::text: + DrawText(Pos, Size, Object->Fg(), Object->Text(), Object->Font(), + Object->Align()); + break; + + case cxObject::marquee: + DrawMarquee(Pos, Size, Object->Fg(), Object->Text(), Object->Font(), + Object->Align(), Object->Delay(), Object->Index()); + break; + + case cxObject::blink: + DrawBlink(Pos, Size, Object->Fg(), Object->Bg(), Object->Text(), + Object->Font(), Object->Align(), Object->Delay(), Object->Index()); + break; + default: + break; + } + + } + } +} + + void cText2SkinRender::DrawImage(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg, const tColor *Mask, int Alpha, int Colors, const std::string &Path) diff --git a/render.h b/render.h index cee31ab..c51bed7 100644 --- a/render.h +++ b/render.h @@ -27,6 +27,7 @@ class cText2SkinRender: public cThread { friend class cText2SkinDisplayReplay; friend class cText2SkinDisplayMessage; friend class cText2SkinDisplayMenu; + friend class cText2SkinDisplayTracks; friend class cText2SkinStatus; @@ -75,6 +76,10 @@ private: }; typedef std::map tStates; tStates mStates; + + // scalefactor for tabs in the menu list + float mTabScale; + bool mTabScaleSet; protected: // Update thread @@ -83,7 +88,11 @@ protected: virtual void Action(void); // Drawing operations - void DrawObject(const cxObject *Object); + void DrawObject(cxObject *Object, const txPoint &BaseOffset=txPoint(-1,-1), + const txSize &BaseSize=txSize(-1,-1), + int ListItem=-1 ); + void DrawItemText(cxObject *o, int i, const txPoint &ListOffset, const txSize &ListSize); + void DrawBackground(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg, int Alpha, const std::string &Path); void DrawImage(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg, diff --git a/xml/display.h b/xml/display.h index 319cc7e..a9b2080 100644 --- a/xml/display.h +++ b/xml/display.h @@ -48,7 +48,7 @@ public: cxSkin *Skin(void) const { return mSkin; } uint Objects(void) const { return mObjects.size(); } - const cxObject *GetObject(int n) const { return mObjects[n]; } + cxObject *GetObject(int n) const { return mObjects[n]; } }; class cxDisplays: public std::map { diff --git a/xml/object.c b/xml/object.c index c63c2ea..81dc854 100644 --- a/xml/object.c +++ b/xml/object.c @@ -155,18 +155,25 @@ const cFont *cxObject::Font(void) const return cFont::GetFont(fontOsd); } -txPoint cxObject::Pos(void) const +txPoint cxObject::Pos(const txPoint &BaseOffset, const txSize &BaseSize) const { - return txPoint(mSkin->BaseOffset().x + (mPos1.x < 0 ? Skin()->BaseSize().w + mPos1.x : mPos1.x), - mSkin->BaseOffset().y + (mPos1.y < 0 ? Skin()->BaseSize().h + mPos1.y : mPos1.y)); + txPoint bOffset = BaseOffset.x < 0 ? mSkin->BaseOffset() : BaseOffset; + txSize bSize = BaseSize.w < 0 ? mSkin->BaseSize() : BaseSize; + + return txPoint(bOffset.x + (mPos1.x < 0 ? bSize.w + mPos1.x : mPos1.x), + bOffset.y + (mPos1.y < 0 ? bSize.h + mPos1.y : mPos1.y)); } -txSize cxObject::Size(void) const +txSize cxObject::Size(const txPoint &BaseOffset, const txSize &BaseSize) const { - txPoint p1(mSkin->BaseOffset().x + (mPos1.x < 0 ? Skin()->BaseSize().w + mPos1.x : mPos1.x), - mSkin->BaseOffset().y + (mPos1.y < 0 ? Skin()->BaseSize().h + mPos1.y : mPos1.y)); - txPoint p2(mSkin->BaseOffset().x + (mPos2.x < 0 ? Skin()->BaseSize().w + mPos2.x : mPos2.x), - mSkin->BaseOffset().y + (mPos2.y < 0 ? Skin()->BaseSize().h + mPos2.y : mPos2.y)); + txPoint bOffset = BaseOffset.x < 0 ? mSkin->BaseOffset() : BaseOffset; + txSize bSize = BaseSize.w < 0 ? mSkin->BaseSize() : BaseSize; + + txPoint p1(bOffset.x + (mPos1.x < 0 ? bSize.w + mPos1.x : mPos1.x), + bOffset.y + (mPos1.y < 0 ? bSize.h + mPos1.y : mPos1.y)); + txPoint p2(bOffset.x + (mPos2.x < 0 ? bSize.w + mPos2.x : mPos2.x), + bOffset.y + (mPos2.y < 0 ? bSize.h + mPos2.y : mPos2.y)); + return txSize(p2.x - p1.x + 1, p2.y - p1.y + 1); } diff --git a/xml/object.h b/xml/object.h index bbc37a0..603019f 100644 --- a/xml/object.h +++ b/xml/object.h @@ -61,7 +61,7 @@ public: item, #define __COUNT_OBJECT__ (item + 1) }; - + private: cxDisplay *mDisplay; cxSkin *mSkin; @@ -118,8 +118,8 @@ public: cxSkin *Skin(void) const { return mSkin; } const std::string &TypeName(void) const; - txPoint Pos(void) const; - txSize Size(void) const; + txPoint Pos(const txPoint &BaseOffset=txPoint(-1,-1), const txSize &BaseSize=txSize(-1,-1)) const; + txSize Size(const txPoint &BaseOffset=txPoint(-1,-1), const txSize &BaseSize=txSize(-1,-1)) const; const cFont *Font(void) const; const tColor *Fg(void) const; const tColor *Bg(void) const; @@ -129,7 +129,7 @@ public: const tColor *Keep(void) const; uint Objects(void) const; - const cxObject *GetObject(uint Index) const; + cxObject *GetObject(uint Index) const; }; class cxObjects: public std::vector { @@ -144,7 +144,7 @@ inline uint cxObject::Objects(void) const return mObjects ? mObjects->size() : 0; } -inline const cxObject *cxObject::GetObject(uint Index) const +inline cxObject *cxObject::GetObject(uint Index) const { return mObjects ? (*mObjects)[Index] : NULL; } -- cgit v1.2.3 From b32f1eaf9ae246f656ebd27c2fbb5d29d2bec34c Mon Sep 17 00:00:00 2001 From: Christian Tusche Date: Sun, 6 May 2007 17:26:51 +0200 Subject: 2007-05-06: Version 1.1-cvs_ext-0.10b (text2skin-1.1-cvs_ext-0.10b.diff) - increase skin file version to 1.1 - the position of list items is interpreted relative to the "list" container when file version >= 1.1 - when a position is specified for "block" elements, the position of all contained elements is interpreted relative to the container position --- HISTORY | 8 ++++++++ loader.c | 5 +++-- render.c | 8 +++++++- text2skin.c | 2 +- xml/parser.c | 4 ++-- xml/skin.c | 34 ++++++++++++++++++++++++++++++++++ xml/skin.h | 42 ++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 95 insertions(+), 8 deletions(-) diff --git a/HISTORY b/HISTORY index 20142fe..bf91d25 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,14 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- +2007-05-06: Version 1.1-cvs_ext-0.10b (text2skin-1.1-cvs_ext-0.10b.diff) + +- increase skin file version to 1.1 +- the position of list items is interpreted relative to the "list" container + when file version >= 1.1 +- when a position is specified for "block" elements, the position of all + contained elements is interpreted relative to the container position + 2007-05-06: Version 1.1-cvs_ext-0.10a (text2skin-1.1-cvs_ext-0.10a.diff) - increased efficiency in drawing list items in the main menu diff --git a/loader.c b/loader.c index a34998b..bdeea09 100644 --- a/loader.c +++ b/loader.c @@ -52,11 +52,12 @@ void cText2SkinLoader::Load(const char *Skin) { cxSkin *skin = xmlParse(Skin, skinfile, translations, theme); if (skin) { - if (skin->Version() == cText2SkinPlugin::SkinVersion()) { + if( skin->Version() <= cText2SkinPlugin::SkinVersion() ) { new cText2SkinLoader(skin, translations, theme, Skin, skin->Title()); return; } else - esyslog("ERROR: text2skin: Skin is version %s, expecting %s", skin->Version().c_str(), + esyslog("ERROR: text2skin: Skin is version %i,%i, expecting <= %s", + skin->Version().Major(), skin->Version().Minor(), cText2SkinPlugin::SkinVersion()); } else esyslog("ERROR: error in skin file"); diff --git a/render.c b/render.c index b300f9e..b068729 100644 --- a/render.c +++ b/render.c @@ -178,7 +178,13 @@ void cText2SkinRender::DrawObject( cxObject *Object, pos = Object->Pos(BaseOffset, BaseSize); - size = Object->Size(BaseOffset, BaseSize); + if( ListItem >= 0 && !mSkin->Version().Require(1,1) ) { + // Object is part of al list + // Calculate offset of list item relative to the list offset + size = Object->Size(); + } else { + size = Object->Size(BaseOffset, BaseSize); + } switch (Object->Type()) { diff --git a/text2skin.c b/text2skin.c index dc41f15..04b3d72 100644 --- a/text2skin.c +++ b/text2skin.c @@ -15,7 +15,7 @@ #include "status.h" const char *cText2SkinPlugin::VERSION = "1.1-cvs_ext-0.10"; -const char *cText2SkinPlugin::SKINVERSION = "1.0"; +const char *cText2SkinPlugin::SKINVERSION = "1.1"; const char *cText2SkinPlugin::DESCRIPTION = "Loader for text-based skins"; cText2SkinPlugin::cText2SkinPlugin(void) { diff --git a/xml/parser.c b/xml/parser.c index f573398..0045af1 100644 --- a/xml/parser.c +++ b/xml/parser.c @@ -45,7 +45,7 @@ #define ATTRIB_OPT_NUMBER(_attr,_target) \ if (attrs.find(_attr) != attrs.end()) { \ char *_e; const char *_t = attrs[_attr].c_str(); \ - long _l = strtol(_t, &_e, 10); \ + long _l = strtol(_t, &_e, 0); \ if (_e ==_t || *_e != '\0') { \ esyslog("ERROR: Text2Skin: Invalid numeric value \"%s\" in attribute %s", \ _t, _attr); \ @@ -91,7 +91,7 @@ bool xStartElem(const std::string &name, std::map &attr if (context.size() == 0) { if (name == "skin") { - ATTRIB_MAN_STRING("version", skin->mVersion); + ATTRIB_MAN_FUNC ("version", skin->mVersion.Parse); ATTRIB_MAN_STRING("name", skin->mTitle); ATTRIB_MAN_FUNC ("screenBase", skin->ParseBase); } diff --git a/xml/skin.c b/xml/skin.c index 6f3e938..5578e1e 100644 --- a/xml/skin.c +++ b/xml/skin.c @@ -9,6 +9,40 @@ const std::string ScreenBases[] = { "relative", "absolute" }; +cxVersion::cxVersion(int ma, int min): + mMajor(ma), + mMinor(min) +{ +} + +bool cxVersion::Parse(const std::string &Text) +{ + int dot = Text.find("."); + std::string ma(Text, 0, dot), min(Text, dot+1); + char *e = NULL; + const char *t = NULL; + long l=0; + + t = ma.c_str(); + l = strtol(t, &e, 10); + if (e ==t || *e != '\0') { + return false; + } else { + mMajor = l; + } + + t = min.c_str(); + l = strtol(t, &e, 10); + if (e ==t || *e != '\0') { + return false; + } else { + mMinor = l; + } + + return true; +} + + cxSkin::cxSkin(const std::string &Name, cText2SkinI18n *I18n, cText2SkinTheme *Theme): mName(Name), mI18n(I18n), diff --git a/xml/skin.h b/xml/skin.h index e27f87e..4613199 100644 --- a/xml/skin.h +++ b/xml/skin.h @@ -15,6 +15,44 @@ class cText2SkinI18n; class cText2SkinTheme; + +class cxVersion { +public: + cxVersion( int ma=0, int min=0 ); + bool Parse(const std::string &Text); + int Major(void) const { return mMajor; } + int Minor(void) const { return mMinor; } + bool Require( int ma, int min ) const { + return mMajor > ma ? true : (mMajor == ma ? mMinor >= min : false); + } + bool Limit( int ma, int min ) const { + return mMajor < ma ? true : (mMajor == ma ? mMinor <= min : false); + } + bool cxVersion::operator==( const cxVersion &v ) const { + return mMajor == v.mMajor && mMinor == v.mMinor; + } + bool cxVersion::operator>=( const cxVersion &v ) const { + return Require( v.mMajor , v.mMinor); + } + bool cxVersion::operator>=( const char *c ) const { + cxVersion v; + if( !v.Parse(c) ) return false; + return Require( v.mMajor , v.mMinor); + } + bool cxVersion::operator<=( const cxVersion &v ) const { + return Limit( v.mMajor , v.mMinor ); + } + bool cxVersion::operator<=( const char *c ) const { + cxVersion v; + if( !v.Parse(c) ) return false; + return Limit( v.mMajor , v.mMinor); + } + +private: + int mMajor; + int mMinor; +}; + class cxSkin { friend bool xStartElem(const std::string &name, std::map &attrs); friend bool xEndElem(const std::string &name); @@ -35,7 +73,7 @@ private: txSize mBaseSize; std::string mName; std::string mTitle; - std::string mVersion; + cxVersion mVersion; cxDisplays mDisplays; @@ -55,7 +93,7 @@ public: const txSize &BaseSize(void) const { return mBaseSize; } const std::string &Name(void) const { return mName; } const std::string &Title(void) const { return mTitle; } - const std::string &Version(void) const { return mVersion; } + const cxVersion &Version(void) const { return mVersion; } // functions for object classes to obtain dynamic item information std::string Translate(const std::string &Text); -- cgit v1.2.3 From f6f140b2ea0bb1de9e055e920ef9c0c43c6e2add Mon Sep 17 00:00:00 2001 From: Christian Tusche Date: Sun, 6 May 2007 17:26:51 +0200 Subject: 2007-05-06: Version 1.1-cvs_ext-0.10c (text2skin-1.1-cvs_ext-0.10c.diff) - selective update of changed objects refresh can be controlled for individual objects by the attributes "refresh" and "changed" default behaviour is to redraw everything (compatible with old skins) --- HISTORY | 7 ++++ display.c | 66 +++++++++++++++++++--------------- render.c | 68 +++++++++++++++++++++++++++-------- render.h | 18 ++++++---- screen.c | 13 ++++++- screen.h | 3 +- xml/display.c | 3 +- xml/display.h | 1 + xml/object.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xml/object.h | 35 ++++++++++++++++++ xml/parser.c | 23 +++++++++++- 11 files changed, 298 insertions(+), 53 deletions(-) diff --git a/HISTORY b/HISTORY index bf91d25..ec4eff1 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,13 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- +2007-05-06: Version 1.1-cvs_ext-0.10c (text2skin-1.1-cvs_ext-0.10c.diff) + +- selective update of changed objects + refresh can be controlled for individual objects by the attributes + "refresh" and "changed" + default behaviour is to redraw everything (compatible with old skins) + 2007-05-06: Version 1.1-cvs_ext-0.10b (text2skin-1.1-cvs_ext-0.10b.diff) - increase skin file version to 1.1 diff --git a/display.c b/display.c index 8c03c12..69a4745 100644 --- a/display.c +++ b/display.c @@ -51,7 +51,7 @@ void cText2SkinDisplayChannel::SetChannel(const cChannel *Channel, int Number) if (mChannel != Channel || mNumber != Number) { mChannel = Channel; mNumber = Number; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -67,7 +67,7 @@ void cText2SkinDisplayChannel::SetEvents(const cEvent *Present, const cEvent *Fo if (mPresent != Present || mFollowing != Following) { mPresent = Present; mFollowing = Following; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -84,7 +84,7 @@ void cText2SkinDisplayChannel::SetMessage(eMessageType Type, const char *Text) if (mType != Type || mText != Text) { mType = Type; mText = Text; - SetDirty(); + SetDirty(cxRefresh::all); } UpdateUnlock(); } @@ -108,7 +108,7 @@ void cText2SkinDisplayChannel::SetButtons(const char *Red, const char *Green, co mButtonGreen = Green; mButtonYellow = Yellow; mButtonBlue = Blue; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -372,7 +372,7 @@ void cText2SkinDisplayVolume::SetVolume(int Current, int Total, bool Mute) mCurrent = Current; mTotal = Total; mMute = Mute; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -422,7 +422,7 @@ void cText2SkinDisplayReplay::SetTitle(const char *Title) if (Title == NULL) Title = ""; if (mTitle != Title) { mTitle = Title; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -436,7 +436,7 @@ void cText2SkinDisplayReplay::SetMode(bool Play, bool Forward, int Speed) mPlay = Play; mForward = Forward; mSpeed = Speed; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -447,7 +447,7 @@ void cText2SkinDisplayReplay::SetProgress(int Current, int Total) if (mCurrent != Current || mTotal != Total) { mCurrent = Current; mTotal = Total; - // SetDirty(); TODO: let this cause a display update every frame? + // SetDirty(cxRefresh::update); TODO: let this cause a display update every frame? } UpdateUnlock(); } @@ -456,7 +456,7 @@ void cText2SkinDisplayReplay::SetMarks(const cMarks *Marks) { UpdateLock(); mMarks = Marks; - SetDirty(); + SetDirty(cxRefresh::update); UpdateUnlock(); } @@ -466,7 +466,7 @@ void cText2SkinDisplayReplay::SetCurrent(const char *Current) if (Current == NULL) Current = ""; if (mPosition != Current) { mPosition = Current; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -477,7 +477,7 @@ void cText2SkinDisplayReplay::SetTotal(const char *Total) if (Total == NULL) Total = ""; if (mDuration != Total) { mDuration = Total; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -488,7 +488,7 @@ void cText2SkinDisplayReplay::SetJump(const char *Jump) if (Jump == NULL) Jump = ""; if (mPrompt != Jump) { mPrompt = Jump; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -500,7 +500,7 @@ void cText2SkinDisplayReplay::SetMessage(eMessageType Type, const char *Text) if (mType != Type || mText != Text) { mType = Type; mText = Text; - SetDirty(); + SetDirty(cxRefresh::all); } UpdateUnlock(); } @@ -519,7 +519,7 @@ void cText2SkinDisplayReplay::SetButtons(const char *Red, const char *Green, con mButtonGreen = Green; mButtonYellow = Yellow; mButtonBlue = Blue; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -677,7 +677,7 @@ void cText2SkinDisplayMessage::SetMessage(eMessageType Type, const char *Text) if (mType != Type || mText != Text) { mType = Type; mText = Text; - SetDirty(); + SetDirty(cxRefresh::all); } UpdateUnlock(); } @@ -778,7 +778,7 @@ void cText2SkinDisplayMenu::Clear(void) ExtRecordingDescription = ""; mText = ""; cText2SkinRender::Clear(); - SetDirty(); + SetDirty(cxRefresh::all); UpdateUnlock(); } @@ -797,7 +797,7 @@ void cText2SkinDisplayMenu::SetTitle(const char *Title) mUpdate.events = true; mUpdate.resetMarquee = true; mTitle = Title; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -821,7 +821,7 @@ void cText2SkinDisplayMenu::SetButtons(const char *Red, const char *Green, const mButtonGreen = Green; mButtonYellow = Yellow; mButtonBlue = Blue; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -839,7 +839,7 @@ void cText2SkinDisplayMenu::SetMessage(eMessageType Type, const char *Text) if (mMessageType != Type || mMessageText != Text) { mMessageType = Type; mMessageText = Text; - SetDirty(); + SetDirty(cxRefresh::all); } UpdateUnlock(); } @@ -865,16 +865,22 @@ void cText2SkinDisplayMenu::SetItem(const char *Text, int Index, bool Current, b if (mItems.size() <= (uint)Index) { mItems.push_back(item); - SetDirty(); + mDirtyItems.push_back( Index ); + SetDirty(cxRefresh::list); } else if (mItems[Index] != item) { mItems[Index] = item; - SetDirty(); + // refresh only the changed items + mDirtyItems.push_back( Index ); + SetDirty(cxRefresh::list); } if (Current && mCurrentItem != (uint)Index) { + // refresh only the changed items + mDirtyItems.push_back( mCurrentItem ); + mDirtyItems.push_back( Index ); + SetDirty(cxRefresh::list); mCurrentItem = Index; - SetDirty(); } if (Current) mRender->mMenuScrollbar.currentOnScreen = (uint)Index; @@ -893,7 +899,7 @@ void cText2SkinDisplayMenu::SetEvent(const cEvent *Event) mEvent = Event; ExtPresentDescription = ""; if (mEvent != NULL) - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -911,7 +917,7 @@ void cText2SkinDisplayMenu::SetRecording(const cRecording *Recording) mRecording = Recording; ExtRecordingDescription = ""; if (mRecording != NULL) - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -927,7 +933,7 @@ void cText2SkinDisplayMenu::SetText(const char *Text, bool FixedFont) if (Text == NULL) Text = ""; if (mText != Text) { mText = Text; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } @@ -953,7 +959,7 @@ void cText2SkinDisplayMenu::Scroll(bool Up, bool Page) UpdateLock(); cText2SkinRender::Scroll(Up, Page); - SetDirty(); + SetDirty(cxRefresh::scroll); UpdateUnlock(); } @@ -1421,9 +1427,13 @@ void cText2SkinDisplayTracks::SetTrack(int Index, const char * const *Tracks) UpdateLock(); Dprintf("SetTrack: %d (%s here, %s in array)\n", Index, Tracks[Index], mItems[Index].c_str()); if (mCurrentItem != (uint)Index) { + // refresh only the changed items + mDirtyItems.push_back( mCurrentItem ); + mDirtyItems.push_back( Index ); mCurrentItem = Index; - SetDirty(); + SetDirty(cxRefresh::list); } + UpdateUnlock(); } @@ -1432,7 +1442,7 @@ void cText2SkinDisplayTracks::SetAudioChannel(int AudioChannel) UpdateLock(); if (mAudioChannel != AudioChannel) { mAudioChannel = AudioChannel; - SetDirty(); + SetDirty(cxRefresh::update); } UpdateUnlock(); } diff --git a/render.c b/render.c index b068729..2537a61 100644 --- a/render.c +++ b/render.c @@ -29,7 +29,7 @@ cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, cxDisplay::eType Di mScreen(NULL), mScroller(NULL), mBasePath(BasePath), - mDirty(true), + mDirty(cxRefresh::all), mFallback(NULL), mActive(false), mDoUpdate(), @@ -37,6 +37,7 @@ cText2SkinRender::cText2SkinRender(cText2SkinLoader *Loader, cxDisplay::eType Di mStarted(), mUpdateIn(0), mNow(0), + mFirst(true), mBaseSize(), mTabScale(1.0), mTabScaleSet(false) @@ -129,12 +130,16 @@ cText2SkinRender::~cText2SkinRender() void cText2SkinRender::Action(void) { + bool to = true; mActive = true; UpdateLock(); mStarted.Broadcast(); while (mActive) { - if (mUpdateIn) mDoUpdate.TimedWait(mDoUpdateMutex, mUpdateIn); - else mDoUpdate.Wait(mDoUpdateMutex); + to = true; + if (mUpdateIn) to=mDoUpdate.TimedWait(mDoUpdateMutex, mUpdateIn); + else mDoUpdate.Wait(mDoUpdateMutex); + + if(!to) SetDirty(cxRefresh::timeout); if (!mActive) break; // fall out if thread to be stopped @@ -150,10 +155,24 @@ void cText2SkinRender::Update(void) //DStartBench(malen); //DStartBench(ges); Dbench(update); +#ifdef BENCH + fprintf( stderr, "mDirty = 0x%04x\n", mDirty ); +#endif + if( mFirst ) { + mDirty = (1<Objects(); ++i) DrawObject(mDisplay->GetObject(i)); + mDirty = 0; + while( mDirtyItems.size() > 0 ) + mDirtyItems.pop_back(); + //DShowBench("---\t", malen); //DStartBench(flushen); Dbench(flush); @@ -168,9 +187,11 @@ void cText2SkinRender::Update(void) void cText2SkinRender::DrawObject( cxObject *Object, const txPoint &BaseOffset /*=txPoint(-1,-1)*/, const txSize &BaseSize /*=txPoint(-1,-1)*/, - int ListItem /*=-1*/ ) + int ListItem /*=-1*/, + bool ForceUpdate /*=false*/) { - if (Object->Condition() != NULL && !Object->Condition()->Evaluate()) + if( !Object->mRefresh.Dirty(mDirty, ForceUpdate) || + (Object->Condition()!=NULL && !Object->Condition()->Evaluate())) return; txPoint pos; @@ -178,13 +199,13 @@ void cText2SkinRender::DrawObject( cxObject *Object, pos = Object->Pos(BaseOffset, BaseSize); - if( ListItem >= 0 && !mSkin->Version().Require(1,1) ) { - // Object is part of al list - // Calculate offset of list item relative to the list offset - size = Object->Size(); - } else { - size = Object->Size(BaseOffset, BaseSize); - } + if( ListItem >= 0 && !mSkin->Version().Require(1,1) ) { + // Object is part of al list + // Calculate offset of list item relative to the list offset + size = Object->Size(); + } else { + size = Object->Size(BaseOffset, BaseSize); + } switch (Object->Type()) { @@ -246,7 +267,8 @@ void cText2SkinRender::DrawObject( cxObject *Object, case cxObject::block: for (uint i = 0; i < Object->Objects(); ++i) - DrawObject(Object->GetObject(i), pos, size, ListItem ); + DrawObject(Object->GetObject(i), pos, size, ListItem, + ListItem >= 0 ? true : Object->mRefresh.Full()); break; case cxObject::list:{ @@ -259,6 +281,14 @@ void cText2SkinRender::DrawObject( cxObject *Object, mMenuScrollbar.maxItems = maxitems; SetMaxItems(maxitems); //Dprintf("setmaxitems %d\n", maxitems); uint index = 0; + bool partial = false; + + // is only a partial update needed? + if( !Object->mRefresh.Full() && + !(Object->mRefresh.Type() & mDirty & ~(1<Objects(); ++j) { item = Object->GetObject(j); + // exclude items with only "list" update set from + // complete redraw + if( !partial && !(item->mRefresh.Type() & + ~(1<SetListIndex( index, -1 ); - DrawObject( item, itempos, itemsize, index ); + DrawObject( item, itempos, itemsize, index, true); } Ddiff( "draw item", item ); } diff --git a/render.h b/render.h index c51bed7..241e908 100644 --- a/render.h +++ b/render.h @@ -48,7 +48,8 @@ private: tTokenCache mTokenCache; std::string mBasePath; - bool mDirty; + uint mDirty; // bit mask of required updates - set by SetDirty() + std::vector mDirtyItems; uint mMaxItems; cSkin *mFallback; @@ -60,6 +61,7 @@ private: cCondVar mStarted; uint mUpdateIn; uint mNow; // timestamp to calculate update timings + bool mFirst; // First drawing of the display -> draw everything // coordinate transformation txSize mBaseSize; @@ -90,7 +92,7 @@ protected: // Drawing operations void DrawObject(cxObject *Object, const txPoint &BaseOffset=txPoint(-1,-1), const txSize &BaseSize=txSize(-1,-1), - int ListItem=-1 ); + int ListItem=-1, bool ForceUpdate=false); void DrawItemText(cxObject *o, int i, const txPoint &ListOffset, const txSize &ListSize); void DrawBackground(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg, @@ -130,7 +132,8 @@ protected: // functions for display renderer to control behaviour void Flush(bool Force = false); - void SetDirty(void) { mDirty = true; } + void SetDirty( cxRefresh::eRefreshType type=cxRefresh::all) { + mDirty |= 1<Scroll(Up, Page); } void Clear(void) { DELETENULL(mScroller); } cSkin *Fallback(void) const { return mFallback; } @@ -179,14 +182,17 @@ public: inline void cText2SkinRender::Flush(bool Force) { - if (mDirty || Force) { + if( Force ) { + // do a full redraw + mDirty = (1 << cxRefresh::all); + } + + if (mDirty>0) { mTokenCache.clear(); UpdateLock(); mDoUpdate.Broadcast(); UpdateUnlock(); - - mDirty = false; } } diff --git a/screen.c b/screen.c index 3412da4..e4dc088 100644 --- a/screen.c +++ b/screen.c @@ -67,7 +67,10 @@ void cText2SkinScreen::DrawBitmap(int x, int y, const cBitmap &Bitmap, const tCo DrawBitmapOverlay(*mRegions[i], x, y, (cBitmap&)Bitmap, ColorMask); //mRegions[i]->DrawBitmap(x, y, Bitmap); #else - mOsd->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg); + // mOsd->DrawBitmap(x, y, Bitmap, ColorFg, ColorBg); + cBitmap *bm = NULL; + for (int i = 0; (bm=mOsd->GetBitmap(i)) != NULL; ++i) + DrawBitmapOverlay(*bm, x, y, (cBitmap&)Bitmap, ColorMask); #endif } @@ -122,6 +125,14 @@ void cText2SkinScreen::Flush(void) mOsd->DrawBitmap(mRegions[i]->X0(), mRegions[i]->Y0(), *mRegions[i]); #endif } +#ifdef BENCH + int x1=0,y1=0,x2=0,y2=0; + cBitmap *bm; + for(int j=0; (bm=mOsd->GetBitmap(j)) != NULL; j++ ) + if(bm->Dirty(x1,y1,x2,y2)) + fprintf(stderr, "Flush dirty screen area %2i: x1=%3i x2=%3i y1=%3i y2=%3i\n", + j,x1,x2,y1,y2 ); +#endif if (!mOffScreen) mOsd->Flush(); } diff --git a/screen.h b/screen.h index a5eee36..7cb447a 100644 --- a/screen.h +++ b/screen.h @@ -8,7 +8,8 @@ #include "common.h" #include -#undef DIRECTBLIT +// #undef DIRECTBLIT +#define DIRECTBLIT class cText2SkinScreen { /* Skin Editor */ diff --git a/xml/display.c b/xml/display.c index a8268c4..adf500b 100644 --- a/xml/display.c +++ b/xml/display.c @@ -11,7 +11,8 @@ static const std::string DisplayNames[] = cxDisplay::cxDisplay(cxSkin *parent): mSkin(parent), mType((eType)__COUNT_DISPLAY__), - mNumWindows(0) + mNumWindows(0), + mRefreshDefault(NULL) { } diff --git a/xml/display.h b/xml/display.h index a9b2080..af1f590 100644 --- a/xml/display.h +++ b/xml/display.h @@ -35,6 +35,7 @@ private: int mNumWindows; int mNumMarquees; cxObjects mObjects; + cxRefresh mRefreshDefault; public: cxDisplay(cxSkin *Parent); diff --git a/xml/object.c b/xml/object.c index 81dc854..587eab5 100644 --- a/xml/object.c +++ b/xml/object.c @@ -30,6 +30,7 @@ cxObject::cxObject(cxDisplay *Parent): mFontWidth(0), mDelay(150), mIndex(0), + mRefresh(this), mObjects(NULL) { } @@ -59,6 +60,7 @@ cxObject::cxObject(const cxObject &Src): mFontSize(Src.mFontSize), mFontWidth(Src.mFontWidth), mDelay(Src.mDelay), + mRefresh(Src.mRefresh), mObjects(NULL) { if (Src.mCondition) @@ -223,3 +225,115 @@ cxObjects::~cxObjects() delete operator[](i); } + + + + + +cxRefresh::cxRefresh( cxObject *Object ): + mRefreshType(0xFF), + mText(NULL), + mChanged(NULL), + mObject(Object), + mForce(true), + mFull(true) +{ +} + +cxRefresh::~cxRefresh() +{ + delete mText; +} + +bool cxRefresh::Dirty(uint dirty, bool force) +{ + bool need_changed = !mForce && !force && !(mRefreshType & dirty & ~(1<Evaluate(); + + if( mEval == mLastEval && need_changed ) { + return false; + } else { + mLastEval = mEval; + } + + return true; +} + + + + + +bool cxRefresh::Parse(const std::string &Text) +{ + uint refresh=0; + bool force=false, full=false; + + if( Text.find("all") != std::string::npos ) + refresh |= (1<Parse(Text) ) { + mChanged = mText; + return true; + } + + return false; +} + +cxRefresh &cxRefresh::operator=(const cxRefresh &a) +{ + mRefreshType = a.mRefreshType; + mForce = a.mForce; + mFull = a.mFull; + return *this; +} diff --git a/xml/object.h b/xml/object.h index 603019f..7a37b5c 100644 --- a/xml/object.h +++ b/xml/object.h @@ -33,6 +33,40 @@ struct txWindow { pos1(_x1, _y2), pos2(_x2, _y2), bpp(_bpp) {} }; +class cxObject; + +class cxRefresh { + friend bool xEndElem(const std::string &name); + +public: + enum eRefreshType { + all, // complete redraw of the screen + timeout, // redraw due to a timeout + //message, // a message was set or removed + update, // update of the osd elements + scroll, // a scroll event + list, // list items or the current item have changed + }; + + cxRefresh(cxObject *Object); + ~cxRefresh(); + bool Dirty(uint dirty, bool force=false); + bool Full(void) const { return mFull; } + uint Type(void) const { return mRefreshType; } + bool Parse(const std::string &Text); + bool ParseChanged(const std::string &Text); + cxRefresh &cxRefresh::operator=(const cxRefresh &b); + +private: + uint mRefreshType; + cxType mLastEval; + cxType mEval; + cxString *mText; + cxString *mChanged; + cxObject *mObject; + bool mForce, mFull; +}; + class cxObjects; class cxObject { @@ -88,6 +122,7 @@ private: int mFontWidth; uint mDelay; uint mIndex; + cxRefresh mRefresh; cxObjects *mObjects; // used for block objects such as public: diff --git a/xml/parser.c b/xml/parser.c index 0045af1..1e3ed73 100644 --- a/xml/parser.c +++ b/xml/parser.c @@ -102,6 +102,7 @@ bool xStartElem(const std::string &name, std::map &attr if (name == "display") { display = new cxDisplay(skin); ATTRIB_MAN_FUNC ("id", display->ParseType); + ATTRIB_OPT_FUNC ("refresh", display->mRefreshDefault.Parse); } else TAG_ERR_REMAIN("skin"); @@ -129,12 +130,18 @@ bool xStartElem(const std::string &name, std::map &attr else { object = new cxObject(display); if (object->ParseType(name)) { + if(parents.size() > 0) + object->mRefresh = parents.back()->mRefresh; + else + object->mRefresh = display->mRefreshDefault; + ATTRIB_OPT_NUMBER("x1", object->mPos1.x); ATTRIB_OPT_NUMBER("y1", object->mPos1.y); ATTRIB_OPT_NUMBER("x2", object->mPos2.x); ATTRIB_OPT_NUMBER("y2", object->mPos2.y); ATTRIB_OPT_FUNC ("condition", object->ParseCondition); - + ATTRIB_OPT_FUNC ("refresh", object->mRefresh.Parse); + ATTRIB_OPT_FUNC ("changed", object->mRefresh.ParseChanged); if (name == "image") { ATTRIB_OPT_NUMBER("x", object->mPos1.x); ATTRIB_OPT_NUMBER("y", object->mPos1.y); @@ -256,6 +263,20 @@ bool xEndElem(const std::string &name) { } } + if (object->mRefresh.mChanged == NULL) { + switch (object->mType) { + case cxObject::text: + case cxObject::marquee: + case cxObject::blink: + case cxObject::scrolltext: + object->mRefresh.mChanged = &object->mText; + break; + + default: + break; + } + } + object->mIndex = oindex++; if (parents.size() > 0) { Dprintf("pushing to parent\n"); -- cgit v1.2.3 From 3ab2393b6932b34e7f0e69af7f843d1303104d79 Mon Sep 17 00:00:00 2001 From: Christian Tusche Date: Sun, 29 Jul 2007 19:01:17 +0200 Subject: 2007-07-29: Version 1.1-cvs_ext-0.11 (text2skin-1.1-cvs_ext-0.11.diff) - moved state tracking of marquee, blink, scroll from cText2SkinRender to cxObject - fixed compatibility with gcc-4 and vdr-1.5.x - fixed use of Update.Lock() in render.h - new: dynamic width/height of objects - new: Option "bgColor" used for items "Text", "Marquee", and "Blink". - remember period to next timeout when doing a non-timeout refresh prevent occasional start/stop of marquee-text --- HISTORY | 11 ++++ common.h | 4 +- render.c | 198 +++++++++++++++++++++++++++++++++++++++++++---------------- render.h | 29 +++------ xml/object.c | 111 +++++++++++++++++++++++++-------- xml/object.h | 49 +++++++++++++-- xml/parser.c | 6 +- xml/skin.h | 10 +-- 8 files changed, 307 insertions(+), 111 deletions(-) diff --git a/HISTORY b/HISTORY index ec4eff1..002f1bd 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,17 @@ VDR Plugin 'text2skin' Revision History --------------------------------------- +2007-07-29: Version 1.1-cvs_ext-0.11 (text2skin-1.1-cvs_ext-0.11.diff) + +- moved state tracking of marquee, blink, scroll from cText2SkinRender + to cxObject +- fixed compatibility with gcc-4 and vdr-1.5.x +- fixed use of Update.Lock() in render.h +- new: dynamic width/height of objects +- new: Option "bgColor" used for items "Text", "Marquee", and "Blink". +- remember period to next timeout when doing a non-timeout refresh + prevent occasional start/stop of marquee-text + 2007-05-06: Version 1.1-cvs_ext-0.10c (text2skin-1.1-cvs_ext-0.10c.diff) - selective update of changed objects diff --git a/common.h b/common.h index f4ec281..9d7b30a 100644 --- a/common.h +++ b/common.h @@ -17,7 +17,7 @@ # else # define Dprintf(x...) # endif -# define Dbench(x) uint64 bench_##x = time_ms() +# define Dbench(x) uint64_t bench_##x = time_ms() # define Ddiff(t,x) fprintf(stderr, "%s took %llu ms\n", t, time_ms() - bench_##x) #else # define Dprintf(x...) @@ -25,7 +25,7 @@ # define Ddiff(t,x) #endif -#define DStartBench(x) uint64 bench_##x = time_ms() +#define DStartBench(x) uint64_t bench_##x = time_ms() #define DShowBench(t,x) fprintf(stderr, "%s took %llu ms\n", t, time_ms() - bench_##x) #if VDRVERSNUM >= 10318 diff --git a/render.c b/render.c index 2537a61..d94911c 100644 --- a/render.c +++ b/render.c @@ -128,32 +128,48 @@ cText2SkinRender::~cText2SkinRender() mRender = NULL; } + + + + void cText2SkinRender::Action(void) { bool to = true; + uint start_time = time_ms(); mActive = true; UpdateLock(); mStarted.Broadcast(); while (mActive) { to = true; - if (mUpdateIn) to=mDoUpdate.TimedWait(mDoUpdateMutex, mUpdateIn); - else mDoUpdate.Wait(mDoUpdateMutex); + start_time = mNow; - if(!to) SetDirty(cxRefresh::timeout); + if( mUpdateIn ) to=mDoUpdate.TimedWait(mDoUpdateMutex, mUpdateIn); + else mDoUpdate.Wait(mDoUpdateMutex); if (!mActive) break; // fall out if thread to be stopped - - mUpdateIn = 0; // has to be re-set within Update(); mNow = time_ms(); + + if( mUpdateIn ) { + if( !to || mNow >= start_time + mUpdateIn ) {\ + SetDirty(cxRefresh::timeout); + mUpdateIn = 0; // has to be re-set within Update(); + } else { + mUpdateIn -= mNow - start_time; + } + } + Update(); } UpdateUnlock(); } + + + + + void cText2SkinRender::Update(void) { - //DStartBench(malen); - //DStartBench(ges); Dbench(update); #ifdef BENCH fprintf( stderr, "mDirty = 0x%04x\n", mDirty ); @@ -173,38 +189,41 @@ void cText2SkinRender::Update(void) while( mDirtyItems.size() > 0 ) mDirtyItems.pop_back(); - //DShowBench("---\t", malen); - //DStartBench(flushen); Dbench(flush); mScreen->Flush(); Ddiff("flush only", flush); Ddiff("complete flush", update); - //DShowBench("===\t", flushen); - //DShowBench("=== ges\t", ges); //printf("====\t%d\n", mDisplay->Objects()); } + + + + + + void cText2SkinRender::DrawObject( cxObject *Object, const txPoint &BaseOffset /*=txPoint(-1,-1)*/, - const txSize &BaseSize /*=txPoint(-1,-1)*/, + const txSize &BaseSize /*=txSize(-1,-1)*/, + const txSize &VirtSize /*=txSize(-1,-1)*/, int ListItem /*=-1*/, bool ForceUpdate /*=false*/) { - if( !Object->mRefresh.Dirty(mDirty, ForceUpdate) || + if( !Object->mRefresh.Dirty(mDirty, mUpdateIn, ForceUpdate, mNow) || (Object->Condition()!=NULL && !Object->Condition()->Evaluate())) return; txPoint pos; txSize size; - pos = Object->Pos(BaseOffset, BaseSize); + pos = Object->Pos(BaseOffset, BaseSize, VirtSize); if( ListItem >= 0 && !mSkin->Version().Require(1,1) ) { // Object is part of al list // Calculate offset of list item relative to the list offset size = Object->Size(); } else { - size = Object->Size(BaseOffset, BaseSize); + size = Object->Size(BaseOffset, BaseSize, VirtSize); } @@ -218,7 +237,7 @@ void cText2SkinRender::DrawObject( cxObject *Object, if( ListItem >= 0 && Object->Display()->Type() == cxDisplay::menu ) DrawItemText( Object, ListItem, pos, BaseSize ); else - DrawText(pos, size, Object->Fg(), Object->Text(), Object->Font(), + DrawText(pos, size, Object->Fg(), Object->Bg(), Object->Text(), Object->Font(), Object->Align()); break; @@ -226,17 +245,17 @@ void cText2SkinRender::DrawObject( cxObject *Object, if( ListItem >= 0 && Object->Display()->Type() == cxDisplay::menu ) DrawItemText( Object, ListItem, pos, BaseSize ); else - DrawMarquee(pos, size, Object->Fg(), Object->Text(), Object->Font(), - Object->Align(), Object->Delay(), Object->Index()); + DrawMarquee(pos, size, Object->Fg(), Object->Bg(), Object->Text(), Object->Font(), + Object->Align(), Object->Delay(), Object->State()); break; case cxObject::blink: if( ListItem >= 0 && Object->Display()->Type() == cxDisplay::menu ) DrawItemText( Object, ListItem, pos, BaseSize ); else - DrawBlink(pos, size, Object->Fg(), Object->Bg(), Object->Text(), + DrawBlink(pos, size, Object->Fg(), Object->Bg(), Object->Bl(), Object->Text(), Object->Font(), Object->Align(), Object->Delay(), - Object->Index()); + Object->State()); break; case cxObject::rectangle: @@ -267,7 +286,7 @@ void cText2SkinRender::DrawObject( cxObject *Object, case cxObject::block: for (uint i = 0; i < Object->Objects(); ++i) - DrawObject(Object->GetObject(i), pos, size, ListItem, + DrawObject(Object->GetObject(i), pos, size, Object->mVirtSize, ListItem, ListItem >= 0 ? true : Object->mRefresh.Full()); break; @@ -304,13 +323,8 @@ void cText2SkinRender::DrawObject( cxObject *Object, itempos.y = pos.y + index * itemsize.h; for (uint j = 1; j < Object->Objects(); ++j) { item = Object->GetObject(j); - // exclude items with only "list" update set from - // complete redraw - if( !partial && !(item->mRefresh.Type() & - ~(1<SetListIndex( index, -1 ); - DrawObject( item, itempos, itemsize, index, true); + DrawObject( item, itempos, itemsize, Object->mVirtSize, index, true); } Ddiff( "draw item", item ); } @@ -346,8 +360,8 @@ void cText2SkinRender::DrawItemText(cxObject *Object, int i, const txPoint &List // for TTF const cFont *defFont = cFont::GetFont(fontOsd); const char *dummy = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "; - if( defFont != Object->Font() ) - mTabScale = 1.05 * (float)Object->Font()->Width(dummy) / (float)defFont->Width(dummy); + //if( defFont != Object->Font() ) + mTabScale = 1.08 * (float)Object->Font()->Width(dummy) / (float)defFont->Width(dummy); mTabScaleSet = true; } @@ -435,18 +449,20 @@ void cText2SkinRender::DrawItemText(cxObject *Object, int i, const txPoint &List } else { switch (Object->Type()) { case cxObject::text: - DrawText(Pos, Size, Object->Fg(), Object->Text(), Object->Font(), - Object->Align()); + DrawText(Pos, Size, Object->Fg(), Object->Bg(), Object->Text(), + Object->Font(), Object->Align()); break; case cxObject::marquee: - DrawMarquee(Pos, Size, Object->Fg(), Object->Text(), Object->Font(), - Object->Align(), Object->Delay(), Object->Index()); + DrawMarquee(Pos, Size, Object->Fg(), Object->Bg(), Object->Text(), + Object->Font(), Object->Align(), Object->Delay(), + Object->State()); break; case cxObject::blink: - DrawBlink(Pos, Size, Object->Fg(), Object->Bg(), Object->Text(), - Object->Font(), Object->Align(), Object->Delay(), Object->Index()); + DrawBlink(Pos, Size, Object->Fg(), Object->Bg(), Object->Bl(), + Object->Text(), Object->Font(), Object->Align(), + Object->Delay(), Object->State()); break; default: break; @@ -473,23 +489,26 @@ void cText2SkinRender::DrawImage(const txPoint &Pos, const txSize &Size, const t } } -void cText2SkinRender::DrawText(const txPoint &Pos, const txSize &Size, const tColor *Fg, - const std::string &Text, const cFont *Font, int Align) +void cText2SkinRender::DrawText(const txPoint &Pos, const txSize &Size, const tColor *Fg, + const tColor *Bg, const std::string &Text, const cFont *Font, int Align) { //Dprintf("trying to draw text %s to %d,%d size %d,%d, color %x\n", Text.c_str(), Pos.x, Pos.y, // Size.w, Size.h, Fg ? *Fg : 0); + if( Bg ) { + mScreen->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, *Bg ); + } + mScreen->DrawText(Pos.x, Pos.y, Text.c_str(), Fg ? *Fg : 0, 0, Font, Size.w, Size.h, Align); } void cText2SkinRender::DrawMarquee(const txPoint &Pos, const txSize &Size, const tColor *Fg, - const std::string &Text, const cFont *Font, int Align, - uint Delay, uint Index) + const tColor *Bg, const std::string &Text, const cFont *Font, + int Align, uint Delay, txState &state) { bool scrolling = Font->Width(Text.c_str()) > Size.w; - tState &state = mStates[Index]; if (state.text != Text) { - state = tState(); + state = txState(); state.text = Text; } @@ -538,22 +557,31 @@ void cText2SkinRender::DrawMarquee(const txPoint &Pos, const txSize &Size, const } //Dprintf("drawMarquee text = %s, state.text = %s, offset = %d, index = %d, scrolling = %d, mUpdatteIn = %d, nexttime = %d, delay = %d\n", // Text.c_str(), state.text.c_str(), state.offset, Index, scrolling, mUpdateIn, state.nexttime, Delay); - + + + if( Bg ) { + mScreen->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, *Bg ); + } + mScreen->DrawText(Pos.x, Pos.y, Text.c_str() + state.offset, Fg ? *Fg : 0, clrTransparent, Font, Size.w, Size.h, Align); } - + + + + + + + void cText2SkinRender::DrawBlink(const txPoint &Pos, const txSize &Size, const tColor *Fg, - const tColor *Bg, const std::string &Text, const cFont *Font, - int Align, uint Delay, uint Index) + const tColor *Bg, const tColor *Bl, const std::string &Text, + const cFont *Font, int Align, uint Delay, txState &state) { - tState &state = mStates[Index]; if (state.text != Text) { - state = tState(); + state = txState(); state.text = Text; } - Dprintf("drawBlink index = %d, state.text = %s, offset = %d\n", Index, state.text.c_str(), - state.offset); + Dprintf("drawBlink state.text = %s, offset = %d\n", state.text.c_str(), state.offset); if (state.nexttime == 0 || mNow >= state.nexttime) { state.nexttime = mNow + Delay; @@ -564,27 +592,53 @@ void cText2SkinRender::DrawBlink(const txPoint &Pos, const txSize &Size, const t if (mUpdateIn == 0 || updatein < mUpdateIn) mUpdateIn = updatein; - const tColor *col = state.offset == 0 ? Fg : Bg; - if (col) + const tColor *col = state.offset == 0 ? Fg : Bl; + + if( Bg ) { + mScreen->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, *Bg ); + } + + if( col ) { mScreen->DrawText(Pos.x, Pos.y, Text.c_str(), *col, clrTransparent, Font, Size.w, Size.h, Align); + } } + + + + + void cText2SkinRender::DrawRectangle(const txPoint &Pos, const txSize &Size, const tColor *Fg) { mScreen->DrawRectangle(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, Fg ? *Fg : 0); } + + + + + void cText2SkinRender::DrawEllipse(const txPoint &Pos, const txSize &Size, const tColor *Fg, int Arc) { mScreen->DrawEllipse(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, Fg ? *Fg : 0, Arc); } + + + + + void cText2SkinRender::DrawSlope(const txPoint &Pos, const txSize &Size, const tColor *Fg, int Arc) { mScreen->DrawSlope(Pos.x, Pos.y, Pos.x + Size.w - 1, Pos.y + Size.h - 1, Fg ? *Fg : 0, Arc); } + + + + + void cText2SkinRender::DrawProgressbar(const txPoint &Pos, const txSize &Size, int Current, int Total, const tColor *Bg, const tColor *Fg, const tColor *Selected, const tColor *Mark, @@ -635,6 +689,11 @@ void cText2SkinRender::DrawProgressbar(const txPoint &Pos, const txSize &Size, i } } + + + + + void cText2SkinRender::DrawMark(const txPoint &Pos, const txSize &Size, bool Start, bool Current, bool Horizontal, const tColor *Mark, const tColor *Cur) { @@ -662,6 +721,11 @@ void cText2SkinRender::DrawMark(const txPoint &Pos, const txSize &Size, bool Sta } } + + + + + void cText2SkinRender::DrawScrolltext(const txPoint &Pos, const txSize &Size, const tColor *Fg, const std::string &Text, const cFont *Font, int /*Align*/) { @@ -672,7 +736,12 @@ void cText2SkinRender::DrawScrolltext(const txPoint &Pos, const txSize &Size, co else mScroller->DrawText(); } - + + + + + + void cText2SkinRender::DrawScrollbar(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg) { @@ -720,12 +789,22 @@ void cText2SkinRender::DrawScrollbar(const txPoint &Pos, const txSize &Size, con } } + + + + + txPoint cText2SkinRender::Transform(const txPoint &Pos) { txSize base = mRender->mBaseSize; return txPoint(Pos.x < 0 ? base.w + Pos.x : Pos.x, Pos.y < 0 ? base.h + Pos.y : Pos.y); } + + + + + bool cText2SkinRender::ItemColor(const std::string &Color, tColor &Result) { if (Color != "" && Color != "None") { @@ -738,6 +817,11 @@ bool cText2SkinRender::ItemColor(const std::string &Color, tColor &Result) return true; } + + + + + std::string cText2SkinRender::ImagePath(const std::string &Filename) { if (mRender) @@ -747,6 +831,11 @@ std::string cText2SkinRender::ImagePath(const std::string &Filename) return ""; } + + + + + cxType cText2SkinRender::GetToken(const txToken &Token) { if (mRender != NULL) { @@ -815,6 +904,11 @@ cxType cText2SkinRender::GetToken(const txToken &Token) return false; } + + + + + cxType cText2SkinRender::GetTokenData(const txToken &Token) { #define MB_PER_MINUTE 25.75 // this is just an estimate! diff --git a/render.h b/render.h index 241e908..f788168 100644 --- a/render.h +++ b/render.h @@ -65,19 +65,6 @@ private: // coordinate transformation txSize mBaseSize; - - // state information for marquee, blink, scroll - struct tState { - bool scrolling; - int offset; - int direction; - uint nexttime; - std::string text; - - tState(void): scrolling(false), offset(0), direction(1), nexttime(0) {} - }; - typedef std::map tStates; - tStates mStates; // scalefactor for tabs in the menu list float mTabScale; @@ -91,7 +78,7 @@ protected: // Drawing operations void DrawObject(cxObject *Object, const txPoint &BaseOffset=txPoint(-1,-1), - const txSize &BaseSize=txSize(-1,-1), + const txSize &BaseSize=txSize(-1,-1), const txSize &VirtSize=txSize(-1,-1), int ListItem=-1, bool ForceUpdate=false); void DrawItemText(cxObject *o, int i, const txPoint &ListOffset, const txSize &ListSize); @@ -99,12 +86,13 @@ protected: int Alpha, const std::string &Path); void DrawImage(const txPoint &Pos, const txSize &Size, const tColor *Bg, const tColor *Fg, const tColor *Mask, int Alpha, int Colors, const std::string &Path); - void DrawText(const txPoint &Pos, const txSize &Size, const tColor *Fg, const std::string &Text, - const cFont *Font, int Align); - void DrawMarquee(const txPoint &Pos, const txSize &Size, const tColor *Fg, - const std::string &Text, const cFont *Font, int Align, uint Delay, uint Index); + void DrawText(const txPoint &Pos, const txSize &Size, const tColor *Fg, const tColor *Bg, + const std::string &Text, const cFont *Font, int Align); + void DrawMarquee(const txPoint &Pos, const txSize &Size, const tColor *Fg, const tColor *Bg, + const std::string &Text, const cFont *Font, int Align, uint Delay, txState &state); void DrawBlink(const txPoint &Pos, const txSize &Size, const tColor *Fg, const tColor *Bg, - const std::string &Text, const cFont *Font, int Align, uint Delay, uint Index); + const tColor *Bl, const std::string &Text, const cFont *Font, int Align, + uint Delay, txState &state); void DrawRectangle(const txPoint &Pos, const txSize &Size, const tColor *Fg); void DrawEllipse(const txPoint &Pos, const txSize &Size, const tColor *Fg, int Arc); void DrawSlope(const txPoint &Pos, const txSize &Size, const tColor *Fg, int Arc); @@ -188,9 +176,8 @@ inline void cText2SkinRender::Flush(bool Force) } if (mDirty>0) { - mTokenCache.clear(); - UpdateLock(); + mTokenCache.clear(); mDoUpdate.Broadcast(); UpdateUnlock(); } diff --git a/xml/object.c b/xml/object.c index 587eab5..eae47e5 100644 --- a/xml/object.c +++ b/xml/object.c @@ -16,6 +16,7 @@ cxObject::cxObject(cxDisplay *Parent): mType((eType)__COUNT_OBJECT__), mPos1(0, 0), mPos2(-1, -1), + mVirtSize(-1,-1), mAlpha(255), mColors(0), mArc(0), @@ -31,7 +32,8 @@ cxObject::cxObject(cxDisplay *Parent): mDelay(150), mIndex(0), mRefresh(this), - mObjects(NULL) + mObjects(NULL), + mListIndex(0) { } @@ -41,11 +43,13 @@ cxObject::cxObject(const cxObject &Src): mType(Src.mType), mPos1(Src.mPos1), mPos2(Src.mPos2), + mVirtSize(Src.mVirtSize), mAlpha(Src.mAlpha), mColors(Src.mColors), mArc(Src.mArc), mFg(Src.mFg), mBg(Src.mBg), + mBl(Src.mBl), mMask(Src.mMask), mMark(Src.mMark), mActive(Src.mActive), @@ -61,7 +65,8 @@ cxObject::cxObject(const cxObject &Src): mFontWidth(Src.mFontWidth), mDelay(Src.mDelay), mRefresh(Src.mRefresh), - mObjects(NULL) + mObjects(NULL), + mListIndex(Src.mListIndex) { if (Src.mCondition) mCondition = new cxFunction(*Src.mCondition); @@ -130,7 +135,8 @@ bool cxObject::ParseFontFace(const std::string &Text) void cxObject::SetListIndex(uint Index, int Tab) { - mIndex = mDisplay->Objects() + (Index * cSkinDisplayMenu::MaxTabs + Tab); + Tab = Tab>=0 ? Tab : -1; + mListIndex = 1 + Index * cSkinDisplayMenu::MaxTabs + Tab; mText.SetListIndex(Index, Tab); mPath.SetListIndex(Index, Tab); if (mCondition != NULL) @@ -157,24 +163,38 @@ const cFont *cxObject::Font(void) const return cFont::GetFont(fontOsd); } -txPoint cxObject::Pos(const txPoint &BaseOffset, const txSize &BaseSize) const +txPoint cxObject::Pos(const txPoint &BaseOffset, const txSize &BaseSize, const txSize &VirtSize) const { txPoint bOffset = BaseOffset.x < 0 ? mSkin->BaseOffset() : BaseOffset; txSize bSize = BaseSize.w < 0 ? mSkin->BaseSize() : BaseSize; - return txPoint(bOffset.x + (mPos1.x < 0 ? bSize.w + mPos1.x : mPos1.x), - bOffset.y + (mPos1.y < 0 ? bSize.h + mPos1.y : mPos1.y)); + double scale_x = VirtSize.w>0 ? (double)BaseSize.w / VirtSize.w : 1.0, + scale_y = VirtSize.h>0 ? (double)BaseSize.h / VirtSize.h : 1.0; + + int x1 = mPos1.x < 0 ? (int)((mPos1.x + 1) * scale_x - 1) : (int)(mPos1.x * scale_x); + int y1 = mPos1.y < 0 ? (int)((mPos1.y + 1) * scale_x - 1) : (int)(mPos1.y * scale_y); + + return txPoint(bOffset.x + (x1 < 0 ? bSize.w + x1 : x1), + bOffset.y + (y1 < 0 ? bSize.h + y1 : y1)); } -txSize cxObject::Size(const txPoint &BaseOffset, const txSize &BaseSize) const +txSize cxObject::Size(const txPoint &BaseOffset, const txSize &BaseSize, const txSize &VirtSize) const { - txPoint bOffset = BaseOffset.x < 0 ? mSkin->BaseOffset() : BaseOffset; + //txPoint bOffset = BaseOffset.x < 0 ? mSkin->BaseOffset() : BaseOffset; txSize bSize = BaseSize.w < 0 ? mSkin->BaseSize() : BaseSize; - txPoint p1(bOffset.x + (mPos1.x < 0 ? bSize.w + mPos1.x : mPos1.x), - bOffset.y + (mPos1.y < 0 ? bSize.h + mPos1.y : mPos1.y)); - txPoint p2(bOffset.x + (mPos2.x < 0 ? bSize.w + mPos2.x : mPos2.x), - bOffset.y + (mPos2.y < 0 ? bSize.h + mPos2.y : mPos2.y)); + double scale_x = VirtSize.w>0 ? (double)BaseSize.w / VirtSize.w : 1.0, + scale_y = VirtSize.h>0 ? (double)BaseSize.h / VirtSize.h : 1.0; + + int x1 = mPos1.x < 0 ? (int)((mPos1.x + 1) * scale_x - 1) : (int)(mPos1.x * scale_x); + int y1 = mPos1.y < 0 ? (int)((mPos1.y + 1) * scale_x - 1) : (int)(mPos1.y * scale_y); + int x2 = mPos2.x < 0 ? (int)((mPos2.x + 1) * scale_x - 1) : (int)(mPos2.x * scale_x); + int y2 = mPos2.y < 0 ? (int)((mPos2.y + 1) * scale_x - 1) : (int)(mPos2.y * scale_y); + + txPoint p1(x1 < 0 ? bSize.w + x1 : x1, + y1 < 0 ? bSize.h + y1 : y1); + txPoint p2(x2 < 0 ? bSize.w + x2 : x2, + y2 < 0 ? bSize.h + y2 : y2); return txSize(p2.x - p1.x + 1, p2.y - p1.y + 1); } @@ -191,6 +211,12 @@ const tColor *cxObject::Bg(void) const return cText2SkinRender::ItemColor(mBg, Bg) ? &Bg : NULL; } +const tColor *cxObject::Bl(void) const +{ + static tColor Bl; + return cText2SkinRender::ItemColor(mBl, Bl) ? &Bl : NULL; +} + const tColor *cxObject::Mask(void) const { static tColor Mask; @@ -230,6 +256,11 @@ cxObjects::~cxObjects() + + +/////////////////////////////////////////////////////////////////////////////// +// ---------- class cxRefresh ---------------------------------------------- // + cxRefresh::cxRefresh( cxObject *Object ): mRefreshType(0xFF), mText(NULL), @@ -245,27 +276,55 @@ cxRefresh::~cxRefresh() delete mText; } -bool cxRefresh::Dirty(uint dirty, bool force) +bool cxRefresh::Dirty(uint dirty, uint &updatein, bool force, uint now) { - bool need_changed = !mForce && !force && !(mRefreshType & dirty & ~(1<State().nexttime; + + bool to = force || mForce || + mObject->Type() == cxObject::block || mObject->Type() == cxObject::list; + bool changed = force || mForce; + + if( now>0 && nexttime>0 ) { + // timeout was set + if( now >= nexttime ) { + // timeout has expired + to = true; + } else { + // time left -> set new update interval + uint nextin = nexttime - now; + if (updatein == 0 || nextin < updatein) + updatein = nextin; + } + } - if( !(mRefreshType & dirty) ) - return false; + // Objaect has changed since last redraw + if( mChanged != NULL ) { + mEval = mChanged->Evaluate(); + if( mEval != mLastEval ) { + changed = true; + } + } - if( mChanged == NULL && need_changed ) - return false; - else if( mChanged == NULL ) + // refresh + if( (mRefreshType & dirty & ~(1<Evaluate(); - - if( mEval == mLastEval && need_changed ) { - return false; - } else { - mLastEval = mEval; + // timeout + if( (mRefreshType & dirty & (1< + // state information for marquee, blink, scroll + uint mListIndex; + typedef std::map tStates; + tStates mStates; + + public: cxObject(cxDisplay *parent); cxObject(const cxObject &Src); @@ -151,13 +188,17 @@ public: uint Index(void) const { return mIndex; } cxDisplay *Display(void) const { return mDisplay; } cxSkin *Skin(void) const { return mSkin; } + txState &State(void) { return mStates[mListIndex]; } const std::string &TypeName(void) const; - txPoint Pos(const txPoint &BaseOffset=txPoint(-1,-1), const txSize &BaseSize=txSize(-1,-1)) const; - txSize Size(const txPoint &BaseOffset=txPoint(-1,-1), const txSize &BaseSize=txSize(-1,-1)) const; + txPoint Pos(const txPoint &BaseOffset=txPoint(-1,-1), const txSize &BaseSize=txSize(-1,-1), + const txSize &VirtSize=txSize(-1,-1) ) const; + txSize Size(const txPoint &BaseOffset=txPoint(-1,-1), const txSize &BaseSize=txSize(-1,-1), + const txSize &VirtSize=txSize(-1,-1)) const; const cFont *Font(void) const; const tColor *Fg(void) const; const tColor *Bg(void) const; + const tColor *Bl(void) const; const tColor *Mask(void) const; const tColor *Mark(void) const; const tColor *Active(void) const; diff --git a/xml/parser.c b/xml/parser.c index 1e3ed73..158724a 100644 --- a/xml/parser.c +++ b/xml/parser.c @@ -159,11 +159,12 @@ bool xStartElem(const std::string &name, std::map &attr || name == "blink" || name == "scrolltext") { ATTRIB_OPT_STRING("color", object->mFg); + ATTRIB_OPT_STRING("bgColor", object->mBg); ATTRIB_OPT_FUNC ("align", object->ParseAlignment); ATTRIB_OPT_FUNC ("font", object->ParseFontFace); if (name == "blink") { - ATTRIB_OPT_STRING("blinkColor", object->mBg); + ATTRIB_OPT_STRING("blinkColor", object->mBl); ATTRIB_OPT_NUMBER("delay", object->mDelay); if (object->mDelay == 0) @@ -196,6 +197,9 @@ bool xStartElem(const std::string &name, std::map &attr else if (name == "item") { ATTRIB_MAN_NUMBER("height", object->mPos2.y); --object->mPos2.y; + } else if (name == "block" || name == "list") { + ATTRIB_OPT_NUMBER("w", object->mVirtSize.w); + ATTRIB_OPT_NUMBER("h", object->mVirtSize.h); } } else TAG_ERR_REMAIN(context[context.size() - 1].c_str()); diff --git a/xml/skin.h b/xml/skin.h index 4613199..69d96e6 100644 --- a/xml/skin.h +++ b/xml/skin.h @@ -28,21 +28,21 @@ public: bool Limit( int ma, int min ) const { return mMajor < ma ? true : (mMajor == ma ? mMinor <= min : false); } - bool cxVersion::operator==( const cxVersion &v ) const { + bool operator==( const cxVersion &v ) const { return mMajor == v.mMajor && mMinor == v.mMinor; } - bool cxVersion::operator>=( const cxVersion &v ) const { + bool operator>=( const cxVersion &v ) const { return Require( v.mMajor , v.mMinor); } - bool cxVersion::operator>=( const char *c ) const { + bool operator>=( const char *c ) const { cxVersion v; if( !v.Parse(c) ) return false; return Require( v.mMajor , v.mMinor); } - bool cxVersion::operator<=( const cxVersion &v ) const { + bool operator<=( const cxVersion &v ) const { return Limit( v.mMajor , v.mMinor ); } - bool cxVersion::operator<=( const char *c ) const { + bool operator<=( const char *c ) const { cxVersion v; if( !v.Parse(c) ) return false; return Limit( v.mMajor , v.mMinor); -- cgit v1.2.3