Removed direct use of Font::wrapText() from OptionListComponent, TextEditComponent and TextListComponent

This commit is contained in:
Leon Styhre 2024-08-12 20:51:52 +02:00
parent 0723ae8364
commit 1d3b2f8066
10 changed files with 85 additions and 52 deletions

View file

@ -352,12 +352,10 @@ private:
// Display the selected entry and left/right option arrows.
for (auto it = mEntries.cbegin(); it != mEntries.cend(); ++it) {
if (it->selected) {
if (it->maxNameLength > 0.0f &&
Font::get(FONT_SIZE_MEDIUM)->sizeText(it->name).x > it->maxNameLength) {
// A maximum length parameter has been passed and the "name" size surpasses
// this value, so abbreviate the string inside the arrows.
auto font = Font::get(FONT_SIZE_MEDIUM);
mText.setText(font->wrapText(it->name, it->maxNameLength));
if (it->maxNameLength > 0.0f) {
// A maximum length parameter is passed to make sure the text is
// abbreviated if it doesn't fit.
mText.setText(it->name, true, it->maxNameLength);
}
else {
mText.setText(it->name);

View file

@ -46,6 +46,7 @@ TextComponent::TextComponent()
, mScrollOffset1 {0.0f}
, mScrollOffset2 {0.0f}
, mScrollTime {0.0f}
, mMaxLength {0.0f}
{
}
@ -62,7 +63,8 @@ TextComponent::TextComponent(const std::string& text,
bool horizontalScrolling,
float scrollSpeedMultiplier,
float scrollDelay,
float scrollGap)
float scrollGap,
float maxLength)
: mFont {nullptr}
, mRenderer {Renderer::getInstance()}
, mColor {0x000000FF}
@ -94,14 +96,18 @@ TextComponent::TextComponent(const std::string& text,
, mScrollOffset1 {0.0f}
, mScrollOffset2 {0.0f}
, mScrollTime {0.0f}
, mMaxLength {maxLength}
{
setFont(font);
setColor(color);
setBackgroundColor(bgcolor);
setHorizontalScrolling(mHorizontalScrolling);
setText(text, false);
setText(text, false, mMaxLength);
setPosition(pos);
setSize(size);
if (mMaxLength == 0.0f)
setSize(size);
else
setSize(glm::vec2 {mMaxLength, size.y});
}
void TextComponent::onSizeChanged()
@ -172,12 +178,13 @@ void TextComponent::setDimming(float dimming)
mTextCache->setDimming(dimming);
}
void TextComponent::setText(const std::string& text, bool update)
void TextComponent::setText(const std::string& text, bool update, float maxLength)
{
if (mText == text)
if (mText == text && mMaxLength == maxLength)
return;
mText = text;
mMaxLength = maxLength;
if (update)
onTextChanged();
@ -475,7 +482,9 @@ void TextComponent::onTextChanged()
if (mFont && mAutoCalcExtent.x) {
mSize = mFont->sizeText(text, mLineSpacing);
if (mSize.x == 0.0f)
if (mMaxLength > 0.0f && mSize.x > mMaxLength)
mSize.x = std::round(mMaxLength);
else if (mSize.x == 0.0f)
return;
}
@ -486,7 +495,8 @@ void TextComponent::onTextChanged()
const float lineHeight {mFont->getHeight(mLineSpacing)};
const bool isScrollable {mParent && mParent->isScrollable()};
const bool isMultiline {mAutoCalcExtent.y == 1 || mSize.y * mRelativeScale > lineHeight};
// Add one extra pixel to lineHeight as the font may be fractional in size.
const bool isMultiline {mAutoCalcExtent.y == 1 || mSize.y * mRelativeScale > lineHeight + 1};
float offsetY {0.0f};
if (mHorizontalScrolling) {

View file

@ -35,14 +35,15 @@ public:
bool horizontalScrolling = false,
float scrollSpeedMultiplier = 1.0f,
float scrollDelay = 1500.0f,
float scrollGap = 1.5f);
float scrollGap = 1.5f,
float maxLength = 0.0f);
void setFont(const std::shared_ptr<Font>& font);
void setUppercase(bool uppercase);
void setLowercase(bool lowercase);
void setCapitalize(bool capitalize);
void onSizeChanged() override;
void setText(const std::string& text, bool update = true);
void setText(const std::string& text, bool update = true, float maxLength = 0.0f);
void setHiddenText(const std::string& text) { mHiddenText = text; }
void setColor(unsigned int color) override;
void setHorizontalAlignment(Alignment align);
@ -188,6 +189,7 @@ private:
float mScrollOffset1;
float mScrollOffset2;
float mScrollTime;
float mMaxLength;
};
#endif // ES_CORE_COMPONENTS_TEXT_COMPONENT_H

View file

@ -28,6 +28,7 @@ TextEditComponent::TextEditComponent()
, mFocused {false}
, mEditing {false}
, mMaskInput {true}
, mMultiLine {false}
, mCursor {0}
, mBlinkTime {0}
, mCursorRepeatDir {0}
@ -76,10 +77,10 @@ void TextEditComponent::onSizeChanged()
onTextChanged(); // Wrap point probably changed.
}
void TextEditComponent::setValue(const std::string& val)
void TextEditComponent::setValue(const std::string& val, bool multiLine, bool update)
{
mText = val;
mTextOrig = val;
mMultiLine = multiLine;
onTextChanged();
onCursorChanged();
}
@ -92,7 +93,7 @@ void TextEditComponent::textInput(const std::string& text, const bool pasting)
#endif
// Allow pasting up to a reasonable max clipboard size.
if (pasting && text.length() > (isMultiline() ? 16384 : 300))
if (pasting && text.length() > (mMultiLine ? 16384 : 300))
return;
if (mEditing) {
@ -106,12 +107,10 @@ void TextEditComponent::textInput(const std::string& text, const bool pasting)
}
}
else {
mText.insert(
mCursor,
(pasting && !isMultiline() ? Utils::String::replace(text, "\n", " ") : text));
mText.insert(mCursor,
(pasting && !mMultiLine ? Utils::String::replace(text, "\n", " ") : text));
mCursor += static_cast<unsigned int>(
(pasting && !isMultiline() ? Utils::String::replace(text, "\n", " ") : text)
.size());
(pasting && !mMultiLine ? Utils::String::replace(text, "\n", " ") : text).size());
}
}
@ -191,7 +190,7 @@ bool TextEditComponent::input(InputConfig* config, Input input)
if (config->getDeviceId() == DEVICE_KEYBOARD) {
// Special handling for keyboard input as the "A" and "B" buttons are overridden.
if (input.id == SDLK_RETURN || input.id == SDLK_KP_ENTER) {
if (isMultiline()) {
if (mMultiLine) {
const bool maskValue {mMaskInput};
mMaskInput = false;
textInput("\n");
@ -311,11 +310,11 @@ void TextEditComponent::setCursor(size_t pos)
void TextEditComponent::onTextChanged()
{
mWrappedText =
(isMultiline() ? getFont()->wrapText(mText, getTextAreaSize().x, 0.0f, 1.5f, true) : mText);
mEditText->setText(mWrappedText);
// Setting the Y size to zero makes the text area expand vertically as needed.
mEditText->setSize(mEditText->getSize().x, 0.0f);
if (mMultiLine)
mEditText->setText(mText, true, mSize.x);
else
mEditText->setText(mText);
mEditText->setColor(mMenuColorKeyboardText | static_cast<unsigned char>(mOpacity * 255.0f));
if (mCursor > static_cast<int>(mText.length()))
@ -324,8 +323,8 @@ void TextEditComponent::onTextChanged()
void TextEditComponent::onCursorChanged()
{
if (isMultiline()) {
mCursorPos = getFont()->getWrappedTextCursorOffset(mWrappedText, mCursor);
if (mMultiLine) {
mCursorPos = getFont()->getWrappedTextCursorOffset(mText, mCursor);
// Need to scroll down?
if (mScrollOffset.y + getTextAreaSize().y < mCursorPos.y + getFont()->getHeight())

View file

@ -29,7 +29,7 @@ public:
void onSizeChanged() override;
void setValue(const std::string& val) override;
void setValue(const std::string& val, bool multiLine, bool update = true);
std::string getValue() const override;
void startEditing();
@ -50,17 +50,15 @@ private:
void updateCursorRepeat(int deltaTime);
void moveCursor(int amt);
bool isMultiline() { return (getSize().y > getFont()->getHeight() * 1.25f); }
glm::vec2 getTextAreaPos() const;
glm::vec2 getTextAreaSize() const;
Renderer* mRenderer;
std::string mText;
std::string mWrappedText;
std::string mTextOrig;
bool mFocused;
bool mEditing;
bool mMaskInput;
bool mMultiLine;
int mCursor; // Cursor position in characters.
int mBlinkTime;

View file

@ -201,11 +201,17 @@ TextListComponent<T>::TextListComponent()
template <typename T>
void TextListComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeData>& theme)
{
entry.data.entryName = std::make_shared<TextComponent>(
mHorizontalScrolling ? entry.name :
mFont->wrapText(entry.name, mSize.x - mHorizontalMargin * 2.0f),
mFont, 0x000000FF, ALIGN_LEFT, ALIGN_CENTER, glm::vec3 {0.0f, 0.0f, 0.0f},
glm::vec2 {mFont->sizeText(entry.name).x, mFont->getSize() * 1.5f});
if (mHorizontalScrolling) {
entry.data.entryName = std::make_shared<TextComponent>(
entry.name, mFont, 0x000000FF, ALIGN_LEFT, ALIGN_CENTER, glm::vec3 {0.0f, 0.0f, 0.0f},
glm::vec2 {mFont->sizeText(entry.name).x, mFont->getSize() * 1.5f});
}
else {
entry.data.entryName = std::make_shared<TextComponent>(
entry.name, mFont, 0x000000FF, ALIGN_LEFT, ALIGN_CENTER, glm::vec3 {0.0f, 0.0f, 0.0f},
glm::vec2 {mFont->sizeText(entry.name).x, mFont->getSize() * 1.5f}, 0x00000000, 1.5f,
1.0f, false, 1.0f, 1500.0f, 1.5f, mSize.x - (mHorizontalMargin * 2.0f));
}
if (mHorizontalScrolling) {
glm::vec2 textSize {entry.data.entryName->getSize()};

View file

@ -135,7 +135,7 @@ GuiTextEditKeyboardPopup::GuiTextEditKeyboardPopup(
glm::ivec2 {mHorizontalKeyCount, static_cast<int>(kbLayout.size()) / 3});
mText = std::make_shared<TextEditComponent>();
mText->setValue(initValue);
mText->setValue(initValue, mMultiLine, false);
// Header.
mGrid.setEntry(mTitle, glm::ivec2 {0, 0}, false, true);
@ -685,12 +685,12 @@ std::shared_ptr<ButtonComponent> GuiTextEditKeyboardPopup::makeButton(
return;
}
else if (key == _("LOAD")) {
mText->setValue(mDefaultValue->getValue());
mText->setValue(mDefaultValue->getValue(), mMultiLine);
mText->setCursor(mDefaultValue->getValue().size());
return;
}
else if (key == _("CLEAR")) {
mText->setValue("");
mText->setValue("", mMultiLine);
return;
}
else if (key == _("CANCEL")) {

View file

@ -56,7 +56,7 @@ GuiTextEditPopup::GuiTextEditPopup(const HelpStyle& helpstyle,
}
mText = std::make_shared<TextEditComponent>();
mText->setValue(initValue);
mText->setValue(initValue, mMultiLine, false);
std::vector<std::shared_ptr<ButtonComponent>> buttons;
buttons.push_back(
@ -67,14 +67,14 @@ GuiTextEditPopup::GuiTextEditPopup(const HelpStyle& helpstyle,
if (mComplexMode) {
buttons.push_back(
std::make_shared<ButtonComponent>(_("LOAD"), loadBtnHelpText, [this, defaultValue] {
mText->setValue(defaultValue);
mText->setValue(defaultValue, mMultiLine);
mText->setCursor(0);
mText->setCursor(defaultValue.size());
}));
}
buttons.push_back(std::make_shared<ButtonComponent>(_("CLEAR"), clearBtnHelpText,
[this] { mText->setValue(""); }));
buttons.push_back(std::make_shared<ButtonComponent>(
_("CLEAR"), clearBtnHelpText, [this] { mText->setValue("", mMultiLine); }));
buttons.push_back(std::make_shared<ButtonComponent>(_("CANCEL"), _("discard changes"),
[this] { delete this; }));

View file

@ -22,6 +22,9 @@ Font::Font(float size, const std::string& path)
, mFontSize {size}
, mLetterHeight {0.0f}
, mMaxGlyphHeight {static_cast<int>(std::round(size))}
, mWrapMaxLength {0.0f}
, mWrapMaxHeight {0.0f}
, mWrapLineSpacing {1.5f}
{
if (mFontSize < 3.0f) {
mFontSize = 3.0f;
@ -195,6 +198,14 @@ std::string Font::wrapText(const std::string& text,
bool addEllipsis {false};
float totalWidth {0.0f};
mWrapMaxLength = maxLength;
mWrapMaxHeight = maxHeight;
mWrapLineSpacing = lineSpacing;
// TODO: Fix this rounding issue properly elsewhere.
if (mWrapMaxHeight < 1.0f)
mWrapMaxHeight = 0.0f;
std::vector<ShapeSegment> segmentsHB;
shapeText(text, segmentsHB);
@ -230,7 +241,7 @@ std::string Font::wrapText(const std::string& text,
break;
}
accumHeight += lineHeight;
if (maxHeight != 0.0f && accumHeight > maxHeight) {
if (mWrapMaxHeight != 0.0f && accumHeight > mWrapMaxHeight) {
addEllipsis = true;
break;
}
@ -272,7 +283,7 @@ std::string Font::wrapText(const std::string& text,
break;
}
else {
if (maxHeight == 0.0f || accumHeight < maxHeight) {
if (mWrapMaxHeight == 0.0f || accumHeight < mWrapMaxHeight) {
// New row.
float spaceOffset {0.0f};
if (lastSpace == wrappedText.size()) {
@ -336,7 +347,7 @@ std::string Font::wrapText(const std::string& text,
return wrappedText;
}
glm::vec2 Font::getWrappedTextCursorOffset(const std::string& wrappedText,
glm::vec2 Font::getWrappedTextCursorOffset(const std::string& text,
const size_t stop,
const float lineSpacing)
{
@ -344,6 +355,9 @@ glm::vec2 Font::getWrappedTextCursorOffset(const std::string& wrappedText,
float yPos {0.0f};
size_t cursor {0};
const std::string wrappedText {
wrapText(text, mWrapMaxLength, mWrapMaxHeight, mWrapLineSpacing, true)};
// TODO: Enable this code when shaped text is properly wrapped in wrapText().
// std::vector<ShapeSegment> segmentsHB;
// shapeText(wrappedText, segmentsHB);
@ -753,9 +767,12 @@ void Font::shapeText(const std::string& text, std::vector<ShapeSegment>& segment
segment.length = static_cast<unsigned int>(textCursor - lastFlushPos);
segment.fontHB = (lastFont == nullptr ? currGlyph->fontHB : lastFont);
segment.doShape = shapeSegment;
#if !defined(NDEBUG)
segment.substring = text.substr(lastFlushPos, textCursor - lastFlushPos);
#else
if (!shapeSegment)
segment.substring = text.substr(lastFlushPos, textCursor - lastFlushPos);
#endif
segmentsHB.emplace_back(std::move(segment));
lastFlushPos = textCursor;

View file

@ -95,7 +95,7 @@ public:
const bool multiLine = false);
// Returns the position of the cursor after moving it to the stop position.
glm::vec2 getWrappedTextCursorOffset(const std::string& wrappedText,
glm::vec2 getWrappedTextCursorOffset(const std::string& text,
const size_t stop,
const float lineSpacing = 1.5f);
@ -248,6 +248,9 @@ private:
float mFontSize;
float mLetterHeight;
int mMaxGlyphHeight;
float mWrapMaxLength;
float mWrapMaxHeight;
float mWrapLineSpacing;
};
// Caching of shaped and rendered text.