diff options
-rw-r--r-- | src/gui/fonts/font.cpp | 72 | ||||
-rw-r--r-- | src/gui/fonts/font.h | 4 | ||||
-rw-r--r-- | src/gui/fonts/font_unittest.cc | 73 | ||||
-rw-r--r-- | src/gui/fonts/textchunk.cpp | 31 | ||||
-rw-r--r-- | src/gui/fonts/textchunk.h | 8 | ||||
-rw-r--r-- | src/gui/fonts/textchunklist.cpp | 22 | ||||
-rw-r--r-- | src/gui/fonts/textchunklist.h | 2 | ||||
-rw-r--r-- | src/gui/widgets/label.cpp | 38 | ||||
-rw-r--r-- | src/gui/widgets/label.h | 9 | ||||
-rw-r--r-- | src/gui/widgets/tabs/tab.cpp | 57 | ||||
-rw-r--r-- | src/gui/widgets/tabs/tab.h | 1 |
11 files changed, 288 insertions, 29 deletions
diff --git a/src/gui/fonts/font.cpp b/src/gui/fonts/font.cpp index 27628aec5..58528f383 100644 --- a/src/gui/fonts/font.cpp +++ b/src/gui/fonts/font.cpp @@ -73,6 +73,7 @@ #include "resources/image.h" #include "resources/imagehelper.h" +#include "utils/delete2.h" #include "utils/files.h" #include "utils/paths.h" #include "utils/sdlcheckutils.h" @@ -316,7 +317,7 @@ void Font::doClean() TextChunkList *const cache = &mCache[f]; const size_t size = static_cast<size_t>(cache->size); #ifdef DEBUG_FONT_COUNTERS - logger->log("ptr: %d, size: %d", f, size); + logger->log("ptr: %u, size: %ld", f, size); #endif if (size > CACHE_SIZE_SMALL3) { @@ -367,3 +368,72 @@ const TextChunkList *Font::getCache() const { return mCache; } + +void Font::generate(TextChunk &chunk) +{ + const std::string &text = chunk.text; + if (text.empty()) + return; + + const unsigned char chr = text[0]; + TextChunkList *const cache = &mCache[chr]; + Color &col = chunk.color; + Color &col2 = chunk.color2; + const int oldAlpha = col.a; + col.a = 255; + + TextChunkSmall key(text, col, col2); + std::map<TextChunkSmall, TextChunk*> &search = cache->search; + std::map<TextChunkSmall, TextChunk*>::iterator i = search.find(key); + if (i != search.end()) + { + TextChunk *const chunk2 = (*i).second; + cache->moveToFirst(chunk2); + //search.erase(key); + cache->remove(chunk2); + chunk.img = chunk2->img; +// logger->log("cached image: " + chunk.text); + } + else + { + if (cache->size >= CACHE_SIZE) + { +#ifdef DEBUG_FONT_COUNTERS + mDeleteCounter ++; +#endif + cache->removeBack(); + } +#ifdef DEBUG_FONT_COUNTERS + mCreateCounter ++; +#endif + const float alpha = static_cast<float>(chunk.color.a) / 255.0F; + chunk.generate(mFont, alpha); +// logger->log("generate image: " + chunk.text); + } + col.a = oldAlpha; +} + +void Font::insertChunk(TextChunk *const chunk) +{ + if (!chunk || chunk->text.empty() || !chunk->img) + return; +// logger->log("insert chunk: text=%s, color: %d,%d,%d", +// chunk->text.c_str(), chunk->color.r, chunk->color.g, chunk->color.b); + const unsigned char chr = chunk->text[0]; + TextChunkList *const cache = &mCache[chr]; + + std::map<TextChunkSmall, TextChunk*> &search = cache->search; + std::map<TextChunkSmall, TextChunk*>::iterator i + = search.find(TextChunkSmall(chunk->text, + chunk->color, chunk->color2)); + if (i != search.end()) + { + delete2(chunk->img); + return; + } + + TextChunk *const chunk2 = new TextChunk(chunk->text, + chunk->color, chunk->color2, chunk->textFont); + chunk2->img = chunk->img; + cache->insertFirst(chunk2); +} diff --git a/src/gui/fonts/font.h b/src/gui/fonts/font.h index 2e0dfad7f..a112673a1 100644 --- a/src/gui/fonts/font.h +++ b/src/gui/fonts/font.h @@ -125,6 +125,10 @@ class Font final int getStringIndexAt(const std::string& text, const int x) const A_WARN_UNUSED; + void generate(TextChunk &chunk); + + void insertChunk(TextChunk *const chunk); + static bool mSoftMode; private: diff --git a/src/gui/fonts/font_unittest.cc b/src/gui/fonts/font_unittest.cc index 8b8d027c5..f41249f96 100644 --- a/src/gui/fonts/font_unittest.cc +++ b/src/gui/fonts/font_unittest.cc @@ -369,7 +369,6 @@ TEST(TextChunkList, clear5) TextChunk *chunk3 = new TextChunk("test3", Color(1, 2, 3), Color(2, 0, 2), nullptr); - chunk1->refCount = 1; list.insertFirst(chunk1); list.insertFirst(chunk2); list.insertFirst(chunk3); @@ -389,6 +388,78 @@ TEST(TextChunkList, clear5) EXPECT_EQ(0, list.searchWidth.size()); } +TEST(TextChunkList, remove1) +{ + TextChunkList list; + int chunksLeft = textChunkCnt; + + TextChunk *chunk = new TextChunk("test", + Color(), Color(), nullptr); + + list.insertFirst(chunk); + list.remove(chunk); + delete chunk; + + EXPECT_EQ(0, list.size); + EXPECT_EQ(nullptr, list.start); + EXPECT_EQ(nullptr, list.end); + EXPECT_EQ(chunksLeft, textChunkCnt); + EXPECT_EQ(0, list.search.size()); + EXPECT_EQ(0, list.searchWidth.size()); +} + +TEST(TextChunkList, remove2) +{ + TextChunkList list; + int chunksLeft = textChunkCnt; + + TextChunk *chunk1 = new TextChunk("test1", + Color(1, 2, 3), Color(2, 0, 0), nullptr); + TextChunk *chunk2 = new TextChunk("test2", + Color(1, 2, 3), Color(2, 0, 1), nullptr); + TextChunk *chunk3 = new TextChunk("test3", + Color(1, 2, 3), Color(2, 0, 2), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.insertFirst(chunk3); + list.remove(chunk1); + delete chunk1; + + EXPECT_EQ(2, list.size); + EXPECT_EQ(chunk3, list.start); + EXPECT_EQ(chunk2, list.end); + EXPECT_EQ(chunksLeft + 2, textChunkCnt); + EXPECT_EQ(2, list.search.size()); + EXPECT_EQ(2, list.searchWidth.size()); +} + +TEST(TextChunkList, remove3) +{ + TextChunkList list; + int chunksLeft = textChunkCnt; + + TextChunk *chunk1 = new TextChunk("test1", + Color(1, 2, 3), Color(2, 0, 0), nullptr); + TextChunk *chunk2 = new TextChunk("test2", + Color(1, 2, 3), Color(2, 0, 1), nullptr); + TextChunk *chunk3 = new TextChunk("test3", + Color(1, 2, 3), Color(2, 0, 2), nullptr); + + list.insertFirst(chunk1); + list.insertFirst(chunk2); + list.insertFirst(chunk3); + list.remove(chunk2); + delete chunk2; + + EXPECT_EQ(2, list.size); + EXPECT_EQ(chunk3, list.start); + EXPECT_EQ(chunk1, list.end); + EXPECT_EQ(chunksLeft + 2, textChunkCnt); + EXPECT_EQ(2, list.search.size()); + EXPECT_EQ(2, list.searchWidth.size()); +} + TEST(TextChunkList, sort1) { TextChunkSmall item1("test line1", diff --git a/src/gui/fonts/textchunk.cpp b/src/gui/fonts/textchunk.cpp index b0933a3e0..a0c8a39dc 100644 --- a/src/gui/fonts/textchunk.cpp +++ b/src/gui/fonts/textchunk.cpp @@ -25,6 +25,8 @@ #include "sdlshared.h" +#include "gui/fonts/font.h" + #include "resources/image.h" #include "resources/surfaceimagehelper.h" @@ -45,10 +47,24 @@ char *strBuf = nullptr; int textChunkCnt = 0; #endif +TextChunk::TextChunk() : + img(nullptr), + textFont(nullptr), + text(), + color(), + color2(), + prev(nullptr), + next(nullptr) +{ +#ifdef UNITTESTS + textChunkCnt ++; +#endif +} + TextChunk::TextChunk(const std::string &text0, const Color &color0, const Color &color1, - const Font *const font) : + Font *const font) : img(nullptr), textFont(font), text(text0), @@ -167,3 +183,16 @@ void TextChunk::generate(TTF_Font *const font, const float alpha) BLOCK_END("TextChunk::generate") } + +void TextChunk::deleteImage() +{ + if (textFont) + { + textFont->insertChunk(this); + img = nullptr; + } + else + { + delete2(img); + } +} diff --git a/src/gui/fonts/textchunk.h b/src/gui/fonts/textchunk.h index 13187473d..6b8beec35 100644 --- a/src/gui/fonts/textchunk.h +++ b/src/gui/fonts/textchunk.h @@ -38,10 +38,12 @@ class Image; class TextChunk final { public: + TextChunk(); + TextChunk(const std::string &text0, const Color &color0, const Color &color1, - const Font *const font); + Font *const font); A_DELETE_COPY(TextChunk) @@ -51,8 +53,10 @@ class TextChunk final void generate(TTF_Font *const font, const float alpha); + void deleteImage(); + Image *img; - const Font *textFont; + Font *textFont; std::string text; Color color; Color color2; diff --git a/src/gui/fonts/textchunklist.cpp b/src/gui/fonts/textchunklist.cpp index bb5cc646f..023727282 100644 --- a/src/gui/fonts/textchunklist.cpp +++ b/src/gui/fonts/textchunklist.cpp @@ -70,6 +70,28 @@ void TextChunkList::moveToFirst(TextChunk *const item) start = item; } +void TextChunkList::remove(TextChunk *const item) +{ + if (!item) + return; + + TextChunk *const oldPrev = item->prev; + TextChunk *const oldNext = item->next; + if (oldPrev) + oldPrev->next = item->next; + else + start = oldNext; + if (oldNext) + oldNext->prev = item->prev; + else + end = oldPrev; + + search.erase(TextChunkSmall(item->text, + item->color, item->color2)); + searchWidth.erase(item->text); + size --; +} + void TextChunkList::removeBack() { TextChunk *oldEnd = end; diff --git a/src/gui/fonts/textchunklist.h b/src/gui/fonts/textchunklist.h index d89a8ab3b..1f5eff0ea 100644 --- a/src/gui/fonts/textchunklist.h +++ b/src/gui/fonts/textchunklist.h @@ -40,6 +40,8 @@ class TextChunkList final void moveToFirst(TextChunk *const item); + void remove(TextChunk *const item); + void removeBack(); void removeBack(int n); diff --git a/src/gui/widgets/label.cpp b/src/gui/widgets/label.cpp index 8b074a0b1..65e7f86d0 100644 --- a/src/gui/widgets/label.cpp +++ b/src/gui/widgets/label.cpp @@ -78,8 +78,10 @@ Label::Label(const Widget2 *const widget) : Widget(widget), ToolTipListener(), mCaption(), + mTextChunk(), mAlignment(Graphics::LEFT), - mPadding(0) + mPadding(0), + mTextChanged(true) { init(); } @@ -89,8 +91,10 @@ Label::Label(const Widget2 *const widget, Widget(widget), ToolTipListener(), mCaption(caption), + mTextChunk(), mAlignment(Graphics::LEFT), - mPadding(0) + mPadding(0), + mTextChanged(true) { const Font *const font = getFont(); if (font) @@ -113,6 +117,7 @@ Label::~Label() theme->unload(mSkin); } removeMouseListener(this); + mTextChunk.deleteImage(); } void Label::init() @@ -160,7 +165,21 @@ void Label::draw(Graphics* graphics) } graphics->setColorAll(mForegroundColor, mForegroundColor2); - font->drawString(graphics, mCaption, textX, textY); + if (mTextChanged) + { + mTextChunk.textFont = font; + mTextChunk.deleteImage(); + mTextChunk.text = mCaption; + mTextChunk.color = mForegroundColor; + mTextChunk.color2 = mForegroundColor2; + font->generate(mTextChunk); + mTextChanged = false; + } + + const Image *const image = mTextChunk.img; + if (image) + graphics->drawImage(image, textX, textY); +// font->drawString(graphics, mCaption, textX, textY); BLOCK_END("Label::draw") } @@ -174,6 +193,9 @@ void Label::adjustSize() void Label::setForegroundColor(const Color &color) { + if (mForegroundColor != color || mForegroundColor2 != color) + mTextChanged = true; +// logger->log("Label::setForegroundColor: " + mCaption); mForegroundColor = color; mForegroundColor2 = color; } @@ -181,6 +203,9 @@ void Label::setForegroundColor(const Color &color) void Label::setForegroundColorAll(const Color &color1, const Color &color2) { + if (mForegroundColor != color1 || mForegroundColor2 != color2) + mTextChanged = true; +// logger->log("Label::setForegroundColorAll: " + mCaption); mForegroundColor = color1; mForegroundColor2 = color2; } @@ -221,3 +246,10 @@ void Label::resizeTo(const int maxSize, const int minSize) setWidth(sz); } } + +void Label::setCaption(const std::string& caption) +{ + if (caption != mCaption) + mTextChanged = true; + mCaption = caption; +} diff --git a/src/gui/widgets/label.h b/src/gui/widgets/label.h index 681908b71..9e82f0a5d 100644 --- a/src/gui/widgets/label.h +++ b/src/gui/widgets/label.h @@ -65,6 +65,8 @@ #ifndef GUI_WIDGETS_LABEL_H #define GUI_WIDGETS_LABEL_H +#include "gui/fonts/textchunk.h" + #include "gui/widgets/widget.h" #include "listeners/tooltiplistener.h" @@ -132,8 +134,7 @@ class Label final : public Widget, * @param caption The caption of the label. * @see getCaption, adjustSize */ - void setCaption(const std::string& caption) - { mCaption = caption; } + void setCaption(const std::string& caption); /** * Sets the alignment of the caption. The alignment is relative @@ -165,12 +166,16 @@ class Label final : public Widget, */ std::string mCaption; + TextChunk mTextChunk; + /** * Holds the alignment of the caption. */ Graphics::Alignment mAlignment; int mPadding; + + bool mTextChanged; }; #endif // GUI_WIDGETS_LABEL_H diff --git a/src/gui/widgets/tabs/tab.cpp b/src/gui/widgets/tabs/tab.cpp index 2f300fb5f..e361c78ff 100644 --- a/src/gui/widgets/tabs/tab.cpp +++ b/src/gui/widgets/tabs/tab.cpp @@ -120,6 +120,7 @@ Tab::Tab(const Widget2 *const widget) : mVertexes(new ImageCollection), mImage(nullptr), mMode(0), + mLabelMode(-1), mHasMouse(false) { init(); @@ -211,37 +212,55 @@ void Tab::draw(Graphics *graphics) // check which type of tab to draw if (mTabbedArea) { + int labelMode = mFlash; + if (mTabbedArea->isTabSelected(this)) { - mLabel->setForegroundColorAll(*mTabSelectedColor, - *mTabSelectedOutlineColor); + labelMode = 3; mode = TAB_SELECTED; // if tab is selected, it doesnt need to highlight activity mFlash = 0; } - else if (mHasMouse) + else if (!labelMode) { - mLabel->setForegroundColorAll(*mTabHighlightedColor, - *mTabHighlightedOutlineColor); - mode = TAB_HIGHLIGHTED; + if (mHasMouse) + { + labelMode = 4; + mode = TAB_HIGHLIGHTED; + } } - else + else if (mHasMouse) { - mLabel->setForegroundColorAll(*mTabColor, *mTabOutlineColor); + mode = TAB_HIGHLIGHTED; } - switch (mFlash) + if (labelMode != mLabelMode) { - case 1: - mLabel->setForegroundColorAll(*mFlashColor, - *mFlashOutlineColor); - break; - case 2: - mLabel->setForegroundColorAll(*mPlayerFlashColor, - *mPlayerFlashOutlineColor); - break; - default: - break; + mLabelMode = labelMode; + switch (labelMode) + { + case 0: // default state + default: + mLabel->setForegroundColorAll(*mTabColor, + *mTabOutlineColor); + break; + case 1: // mFlash == 1 + mLabel->setForegroundColorAll(*mFlashColor, + *mFlashOutlineColor); + break; + case 2: // mFlash == 2 + mLabel->setForegroundColorAll(*mPlayerFlashColor, + *mPlayerFlashOutlineColor); + break; + case 3: //mTabbedArea->isTabSelected(this) + mLabel->setForegroundColorAll(*mTabSelectedColor, + *mTabSelectedOutlineColor); + break; + case 4: // mHasMouse + mLabel->setForegroundColorAll(*mTabHighlightedColor, + *mTabHighlightedOutlineColor); + break; + } } } diff --git a/src/gui/widgets/tabs/tab.h b/src/gui/widgets/tabs/tab.h index 06b5a3d18..8b26ee3d4 100644 --- a/src/gui/widgets/tabs/tab.h +++ b/src/gui/widgets/tabs/tab.h @@ -228,6 +228,7 @@ class Tab notfinal : public BasicContainer, ImageCollection *mVertexes; Image *mImage; int mMode; + int mLabelMode; protected: bool mHasMouse; |