mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-17 00:30:26 -05:00
Added a simple text area UI node (#277)
This commit is contained in:
parent
275a87aece
commit
7f277a77e1
2 changed files with 288 additions and 0 deletions
60
loader/include/Geode/ui/TextArea.hpp
Normal file
60
loader/include/Geode/ui/TextArea.hpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
#include <cocos2d.h>
|
||||
|
||||
namespace geode {
|
||||
/**
|
||||
* A class which provides a textarea with proper alignment and some extra features like:
|
||||
*
|
||||
* - Max lines
|
||||
* - Changing all aspects after creation
|
||||
* - Custom text alignment
|
||||
* - Automatic line wrapping and cutoff
|
||||
* - Line padding
|
||||
*
|
||||
* Contact me on Discord (\@smjs) if you have any questions, suggestions or bugs.
|
||||
*/
|
||||
class GEODE_DLL SimpleTextArea : public cocos2d::CCNode {
|
||||
cocos2d::CCMenu* m_container;
|
||||
std::string m_font;
|
||||
std::string m_text;
|
||||
std::vector<cocos2d::CCLabelBMFont*> m_lines;
|
||||
cocos2d::CCTextAlignment m_alignment;
|
||||
size_t m_maxLines;
|
||||
float m_scale;
|
||||
float m_lineHeight;
|
||||
float m_linePadding;
|
||||
bool m_artificialWidth;
|
||||
public:
|
||||
static SimpleTextArea* create(const std::string& font, const std::string& text, const float scale);
|
||||
static SimpleTextArea* create(const std::string& font, const std::string& text, const float scale, const float width);
|
||||
|
||||
void setFont(const std::string& font);
|
||||
std::string getFont();
|
||||
void setAlignment(const cocos2d::CCTextAlignment alignment);
|
||||
cocos2d::CCTextAlignment getAlignment();
|
||||
void setText(const std::string& text);
|
||||
std::string getText();
|
||||
void setMaxLines(const size_t maxLines);
|
||||
size_t getMaxLines();
|
||||
void setWidth(const float width);
|
||||
float getWidth();
|
||||
void setScale(const float scale);
|
||||
float getScale();
|
||||
void setLinePadding(const float padding);
|
||||
float getLinePadding();
|
||||
std::vector<cocos2d::CCLabelBMFont*> getLines();
|
||||
float getHeight();
|
||||
float getLineHeight();
|
||||
private:
|
||||
static SimpleTextArea* create(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth);
|
||||
|
||||
SimpleTextArea(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth);
|
||||
cocos2d::CCLabelBMFont* createLabel(const std::string& text, const float top);
|
||||
cocos2d::CCLabelBMFont* moveOverflow(cocos2d::CCLabelBMFont* line, const char c, const float top);
|
||||
float calculateOffset(cocos2d::CCLabelBMFont* label);
|
||||
void updateLines();
|
||||
void updateContents();
|
||||
};
|
||||
}
|
228
loader/src/ui/nodes/TextArea.cpp
Normal file
228
loader/src/ui/nodes/TextArea.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
#include <Geode/ui/TextArea.hpp>
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
SimpleTextArea* SimpleTextArea::create(const std::string& font, const std::string& text, const float scale = 1) {
|
||||
return SimpleTextArea::create(font, text, scale, 500, false);
|
||||
}
|
||||
|
||||
SimpleTextArea* SimpleTextArea::create(const std::string& font, const std::string& text, const float scale, const float width) {
|
||||
return SimpleTextArea::create(font, text, scale, width, true);
|
||||
}
|
||||
|
||||
SimpleTextArea* SimpleTextArea::create(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth) {
|
||||
SimpleTextArea* instance = new SimpleTextArea(font, text, scale, width, artificialWidth);
|
||||
|
||||
if (instance && instance->init()) {
|
||||
instance->autorelease();
|
||||
|
||||
return instance;
|
||||
} else {
|
||||
CC_SAFE_DELETE(instance);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTextArea::SimpleTextArea(const std::string& font, const std::string& text, const float scale, const float width, const bool artificialWidth) {
|
||||
m_font = font;
|
||||
m_text = text;
|
||||
m_maxLines = 0;
|
||||
m_scale = scale;
|
||||
m_linePadding = 0;
|
||||
m_artificialWidth = artificialWidth;
|
||||
m_container = CCMenu::create();
|
||||
|
||||
this->setAnchorPoint({ 0.5f, 0.5f });
|
||||
m_container->setPosition({ 0, 0 });
|
||||
m_container->setAnchorPoint({ 0, 1 });
|
||||
m_container->setContentSize({ width, 0 });
|
||||
|
||||
this->addChild(m_container);
|
||||
this->updateContents();
|
||||
}
|
||||
|
||||
void SimpleTextArea::setFont(const std::string& font) {
|
||||
m_font = font;
|
||||
|
||||
this->updateContents();
|
||||
}
|
||||
|
||||
std::string SimpleTextArea::getFont() {
|
||||
return m_font;
|
||||
}
|
||||
|
||||
void SimpleTextArea::setAlignment(const CCTextAlignment alignment) {
|
||||
m_alignment = alignment;
|
||||
|
||||
this->updateContents();
|
||||
}
|
||||
|
||||
CCTextAlignment SimpleTextArea::getAlignment() {
|
||||
return m_alignment;
|
||||
}
|
||||
|
||||
void SimpleTextArea::setText(const std::string& text) {
|
||||
m_text = text;
|
||||
|
||||
this->updateContents();
|
||||
}
|
||||
|
||||
std::string SimpleTextArea::getText() {
|
||||
return m_text;
|
||||
}
|
||||
|
||||
void SimpleTextArea::setMaxLines(const size_t maxLines) {
|
||||
m_maxLines = maxLines;
|
||||
|
||||
this->updateContents();
|
||||
}
|
||||
|
||||
size_t SimpleTextArea::getMaxLines() {
|
||||
return m_maxLines;
|
||||
}
|
||||
|
||||
void SimpleTextArea::setWidth(const float width) {
|
||||
m_artificialWidth = true;
|
||||
|
||||
this->setContentSize({ width, this->getContentSize().height });
|
||||
m_container->setContentSize(this->getContentSize());
|
||||
}
|
||||
|
||||
float SimpleTextArea::getWidth() {
|
||||
return m_container->getContentSize().width;
|
||||
}
|
||||
|
||||
void SimpleTextArea::setScale(const float scale) {
|
||||
m_scale = scale;
|
||||
|
||||
this->updateContents();
|
||||
}
|
||||
|
||||
float SimpleTextArea::getScale() {
|
||||
return m_scale;
|
||||
}
|
||||
|
||||
void SimpleTextArea::setLinePadding(const float padding) {
|
||||
m_linePadding = padding;
|
||||
|
||||
this->updateContents();
|
||||
}
|
||||
|
||||
float SimpleTextArea::getLinePadding() {
|
||||
return m_linePadding;
|
||||
}
|
||||
|
||||
std::vector<CCLabelBMFont*> SimpleTextArea::getLines() {
|
||||
return m_lines;
|
||||
}
|
||||
|
||||
float SimpleTextArea::getHeight() {
|
||||
return m_container->getContentSize().height;
|
||||
}
|
||||
|
||||
float SimpleTextArea::getLineHeight() {
|
||||
return m_lineHeight;
|
||||
}
|
||||
|
||||
CCLabelBMFont* SimpleTextArea::createLabel(const std::string& text, const float top) {
|
||||
CCLabelBMFont* label = CCLabelBMFont::create(text.c_str(), m_font.c_str());
|
||||
|
||||
label->setScale(m_scale);
|
||||
label->setAnchorPoint({ 0, 0 });
|
||||
label->setPosition({ 0, top });
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
CCLabelBMFont* SimpleTextArea::moveOverflow(CCLabelBMFont* line, const char c, const float top) {
|
||||
const std::string text = line->getString();
|
||||
const char back = text.back();
|
||||
const bool lastIsSpace = back == ' ';
|
||||
CCLabelBMFont* newLine = this->createLabel(std::string(!lastIsSpace, back).append(std::string(c != ' ', c)), top);
|
||||
|
||||
if (!lastIsSpace) {
|
||||
if (text[text.size() - 2] == ' ') {
|
||||
line->setString(text.substr(0, text.size() - 1).c_str());
|
||||
} else {
|
||||
line->setString((text.substr(0, text.size() - 1) + '-').c_str());
|
||||
}
|
||||
}
|
||||
|
||||
m_lines.push_back(newLine);
|
||||
|
||||
return newLine;
|
||||
}
|
||||
|
||||
float SimpleTextArea::calculateOffset(CCLabelBMFont* label) {
|
||||
return m_linePadding + label->getContentSize().height * m_scale;
|
||||
}
|
||||
|
||||
void SimpleTextArea::updateLines() {
|
||||
float top = 0;
|
||||
CCLabelBMFont* line = this->createLabel("", top);
|
||||
m_lines = { line };
|
||||
|
||||
for (const char c : m_text) {
|
||||
if (m_maxLines && m_lines.size() > m_maxLines) {
|
||||
CCLabelBMFont* last = m_lines.at(m_maxLines - 1);
|
||||
const std::string text = last->getString();
|
||||
|
||||
m_lines.pop_back();
|
||||
last->setString(text.substr(0, text.size() - 3).append("...").c_str());
|
||||
|
||||
break;
|
||||
} else if (c == '\n') {
|
||||
line = this->createLabel("", top -= this->calculateOffset(line));
|
||||
|
||||
m_lines.push_back(line);
|
||||
} else if (m_artificialWidth && line->getContentSize().width >= this->getWidth()) {
|
||||
line = this->moveOverflow(line, c, top -= this->calculateOffset(line));
|
||||
} else {
|
||||
const std::string text = line->getString();
|
||||
|
||||
line->setString((text + c).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTextArea::updateContents() {
|
||||
this->updateLines();
|
||||
const size_t lineCount = m_lines.size();
|
||||
const float width = this->getWidth();
|
||||
|
||||
if (lineCount > 0) {
|
||||
m_lineHeight = m_lines.back()->getContentSize().height * m_scale;
|
||||
} else {
|
||||
m_lineHeight = 0;
|
||||
}
|
||||
|
||||
float height = m_lineHeight * lineCount + m_linePadding * (lineCount - 1);
|
||||
|
||||
this->setContentSize({ width, height });
|
||||
m_container->setContentSize(this->getContentSize());
|
||||
m_container->removeAllChildren();
|
||||
|
||||
height -= m_lineHeight;
|
||||
|
||||
for (CCLabelBMFont* line : m_lines) {
|
||||
const float y = height + line->getPositionY();
|
||||
|
||||
switch (m_alignment) {
|
||||
case kCCTextAlignmentLeft: {
|
||||
line->setAnchorPoint({ 0, 0 });
|
||||
line->setPosition({ 0, y });
|
||||
} break;
|
||||
case kCCTextAlignmentCenter: {
|
||||
line->setAnchorPoint({ 0.5f, 0 });
|
||||
line->setPosition({ width / 2, y });
|
||||
} break;
|
||||
case kCCTextAlignmentRight: {
|
||||
line->setAnchorPoint({ 1, 0 });
|
||||
line->setPosition({ width, y });
|
||||
} break;
|
||||
}
|
||||
|
||||
m_container->addChild(line);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue