Label cache

This commit is contained in:
MihailRis
2024-04-24 23:24:47 +03:00
parent 4ac8ea1ab3
commit 37e089169e
2 changed files with 60 additions and 41 deletions
+41 -37
View File
@@ -1,5 +1,4 @@
#include "Label.hpp" #include "Label.hpp"
#include "../../core/GfxContext.hpp" #include "../../core/GfxContext.hpp"
#include "../../core/Batch2D.hpp" #include "../../core/Batch2D.hpp"
#include "../../core/Font.hpp" #include "../../core/Font.hpp"
@@ -8,12 +7,30 @@
using namespace gui; using namespace gui;
void LabelCache::update(const std::wstring& text, bool multiline) {
resetFlag = false;
lines.clear();
if (multiline) {
lines.push_back(LineScheme {0});
for (size_t i = 0; i < text.length(); i++) {
if (text[i] == L'\n') {
lines.push_back(LineScheme {i+1});
}
}
}
if (lines.empty()) {
lines.push_back(LineScheme {0});
}
}
Label::Label(std::string text, std::string fontName) Label::Label(std::string text, std::string fontName)
: UINode(glm::vec2(text.length() * 8, 15)), : UINode(glm::vec2(text.length() * 8, 15)),
text(util::str2wstr_utf8(text)), text(util::str2wstr_utf8(text)),
fontName(fontName) fontName(fontName)
{ {
setInteractive(false); setInteractive(false);
cache.update(this->text, multiline);
} }
@@ -23,17 +40,15 @@ Label::Label(std::wstring text, std::string fontName)
fontName(fontName) fontName(fontName)
{ {
setInteractive(false); setInteractive(false);
cache.update(this->text, multiline);
} }
void Label::setText(std::wstring text) { void Label::setText(std::wstring text) {
this->text = text; if (text == this->text && !cache.resetFlag) {
lines = 1; return;
for (size_t i = 0; i < text.length(); i++) {
if (text[i] == L'\n') {
lines++;
}
} }
lines = std::max(lines, 1U); this->text = text;
cache.update(this->text, multiline);
} }
const std::wstring& Label::getText() const { const std::wstring& Label::getText() const {
@@ -68,18 +83,9 @@ int Label::getTextYOffset() const {
return textYOffset; return textYOffset;
} }
size_t Label::getTextLineOffset(uint line) const { size_t Label::getTextLineOffset(size_t line) const {
size_t offset = 0; line = std::min(cache.lines.size()-1, line);
size_t linesCount = 0; return cache.lines.at(line).offset;
while (linesCount < line && offset < text.length()) {
size_t endline = text.find(L'\n', offset);
if (endline == std::wstring::npos) {
break;
}
offset = endline+1;
linesCount++;
}
return offset;
} }
int Label::getLineYOffset(uint line) const { int Label::getLineYOffset(uint line) const {
@@ -94,24 +100,16 @@ uint Label::getLineByYOffset(int offset) const {
} }
uint Label::getLineByTextIndex(size_t index) const { uint Label::getLineByTextIndex(size_t index) const {
size_t offset = 0; for (size_t i = 0; i < cache.lines.size(); i++) {
size_t linesCount = 0; if (cache.lines.at(i).offset > index) {
while (offset < index && offset < text.length()) { return i-1;
size_t endline = text.find(L'\n', offset);
if (endline == std::wstring::npos) {
break;
} }
if (endline+1 > index) {
break;
}
offset = endline+1;
linesCount++;
} }
return linesCount; return cache.lines.size()-1;
} }
uint Label::getLinesNumber() const { uint Label::getLinesNumber() const {
return lines; return cache.lines.size();
} }
void Label::draw(const GfxContext* pctx, Assets* assets) { void Label::draw(const GfxContext* pctx, Assets* assets) {
@@ -125,10 +123,13 @@ void Label::draw(const GfxContext* pctx, Assets* assets) {
batch->setColor(getColor()); batch->setColor(getColor());
uint lineHeight = font->getLineHeight(); uint lineHeight = font->getLineHeight();
if (cache.lines.size() > 1) {
lineHeight *= lineInterval;
}
glm::vec2 size = getSize(); glm::vec2 size = getSize();
glm::vec2 newsize ( glm::vec2 newsize (
font->calcWidth(text), font->calcWidth(text),
(lines == 1 ? lineHeight : lineHeight*lineInterval)*lines + font->getYOffset() lineHeight * cache.lines.size() + font->getYOffset()
); );
glm::vec2 pos = calcPos(); glm::vec2 pos = calcPos();
@@ -153,11 +154,11 @@ void Label::draw(const GfxContext* pctx, Assets* assets) {
break; break;
} }
textYOffset = pos.y-calcPos().y; textYOffset = pos.y-calcPos().y;
totalLineHeight = lineHeight * lineInterval; totalLineHeight = lineHeight;
if (multiline) { if (multiline) {
size_t offset = 0; size_t offset = 0;
for (uint i = 0; i < lines; i++) { for (uint i = 0; i < cache.lines.size(); i++) {
std::wstring_view view(text.c_str()+offset, text.length()-offset); std::wstring_view view(text.c_str()+offset, text.length()-offset);
size_t end = view.find(L'\n'); size_t end = view.find(L'\n');
if (end != std::wstring::npos) { if (end != std::wstring::npos) {
@@ -177,7 +178,10 @@ void Label::textSupplier(wstringsupplier supplier) {
void Label::setMultiline(bool multiline) { void Label::setMultiline(bool multiline) {
this->multiline = multiline; if (multiline != this->multiline) {
this->multiline = multiline;
cache.resetFlag = true;
}
} }
bool Label::isMultiline() const { bool Label::isMultiline() const {
+19 -4
View File
@@ -4,18 +4,33 @@
#include "UINode.hpp" #include "UINode.hpp"
namespace gui { namespace gui {
struct LineScheme {
size_t offset;
};
struct LabelCache {
std::vector<LineScheme> lines;
/// @brief Reset cache flag
bool resetFlag = true;
void update(const std::wstring& text, bool multiline);
};
class Label : public UINode { class Label : public UINode {
LabelCache cache;
protected: protected:
std::wstring text; std::wstring text;
std::string fontName; std::string fontName;
wstringsupplier supplier = nullptr; wstringsupplier supplier = nullptr;
uint lines = 1;
/// @brief Lines interval multiplier
float lineInterval = 1.5f; float lineInterval = 1.5f;
/// @brief Vertical alignment (only when multiline is set to false)
Align valign = Align::center; Align valign = Align::center;
/// @brief Line separators will be ignored if set to false
bool multiline = false; bool multiline = false;
// runtime values
/// @brief Text Y offset relative to label position /// @brief Text Y offset relative to label position
/// (last calculated alignment) /// (last calculated alignment)
@@ -57,7 +72,7 @@ namespace gui {
/// @brief Get position of line start in the text /// @brief Get position of line start in the text
/// @param line target line index /// @param line target line index
/// @return position in the text [0..length] /// @return position in the text [0..length]
virtual size_t getTextLineOffset(uint line) const; virtual size_t getTextLineOffset(size_t line) const;
/// @brief Get line index by its Y offset relative to label position /// @brief Get line index by its Y offset relative to label position
/// @param offset target Y offset /// @param offset target Y offset