Label cache
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -4,19 +4,34 @@
|
|||||||
#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)
|
||||||
int textYOffset = 0;
|
int textYOffset = 0;
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user