Extra2D/src/ui/text.cpp

247 lines
4.9 KiB
C++
Raw Normal View History

#include <core/string.h>
2026-02-11 19:40:26 +08:00
#include <cstdarg>
#include <cstdio>
#include <graphics/render_backend.h>
#include <ui/text.h>
2026-02-11 19:40:26 +08:00
namespace extra2d {
/**
* @brief
*/
Text::Text() { setAnchor(0.0f, 0.0f); }
2026-02-11 19:40:26 +08:00
/**
* @brief
* @param text
*/
2026-02-11 19:40:26 +08:00
Text::Text(const std::string &text) : text_(text) {
sizeDirty_ = true;
setAnchor(0.0f, 0.0f);
}
/**
* @brief
* @param text
*/
2026-02-11 19:40:26 +08:00
void Text::setText(const std::string &text) {
text_ = text;
sizeDirty_ = true;
updateSpatialIndex();
}
/**
* @brief
* @param font
*/
2026-02-11 19:40:26 +08:00
void Text::setFont(Ptr<FontAtlas> font) {
font_ = font;
sizeDirty_ = true;
updateSpatialIndex();
}
/**
* @brief
* @param color
*/
2026-02-11 19:40:26 +08:00
void Text::setTextColor(const Color &color) { color_ = color; }
/**
* @brief
* @param size
*/
2026-02-11 19:40:26 +08:00
void Text::setFontSize(int size) {
fontSize_ = size;
sizeDirty_ = true;
updateSpatialIndex();
}
/**
* @brief
* @param align
*/
2026-02-11 19:40:26 +08:00
void Text::setAlignment(Alignment align) {
alignment_ = align;
updateSpatialIndex();
}
/**
* @brief
* @param align
*/
2026-02-11 19:40:26 +08:00
void Text::setVerticalAlignment(VerticalAlignment align) {
verticalAlignment_ = align;
updateSpatialIndex();
}
/**
* @brief
* @return
*/
2026-02-11 19:40:26 +08:00
Vec2 Text::getTextSize() const {
updateCache();
return cachedSize_;
}
/**
* @brief
* @return
*/
2026-02-11 19:40:26 +08:00
float Text::getLineHeight() const {
if (font_) {
return font_->getLineHeight();
}
return static_cast<float>(fontSize_);
}
/**
* @brief
*/
2026-02-11 19:40:26 +08:00
void Text::updateCache() const {
if (!sizeDirty_ || !font_) {
return;
}
cachedSize_ = font_->measureText(text_);
sizeDirty_ = false;
}
/**
* @brief
* @return
*/
2026-02-11 19:40:26 +08:00
Vec2 Text::calculateDrawPosition() const {
Vec2 position = pos();
2026-02-11 19:40:26 +08:00
Vec2 textSize = getTextSize();
Size widgetSize = size();
Vec2 anchorPt = anchor();
2026-02-11 19:40:26 +08:00
float refWidth = widgetSize.empty() ? textSize.x : widgetSize.width;
float refHeight = widgetSize.empty() ? textSize.y : widgetSize.height;
position.x -= textSize.x * anchorPt.x;
position.y -= textSize.y * anchorPt.y;
2026-02-11 19:40:26 +08:00
if (!widgetSize.empty()) {
switch (alignment_) {
case Alignment::Center:
position.x += (refWidth - textSize.x) * 0.5f;
break;
case Alignment::Right:
position.x += refWidth - textSize.x;
break;
case Alignment::Left:
default:
break;
2026-02-11 19:40:26 +08:00
}
}
if (!widgetSize.empty()) {
switch (verticalAlignment_) {
case VerticalAlignment::Middle:
position.y += (refHeight - textSize.y) * 0.5f;
break;
case VerticalAlignment::Bottom:
position.y += refHeight - textSize.y;
break;
case VerticalAlignment::Top:
default:
break;
2026-02-11 19:40:26 +08:00
}
}
return position;
2026-02-11 19:40:26 +08:00
}
/**
* @brief
* @return
*/
2026-02-11 19:40:26 +08:00
Ptr<Text> Text::create() { return makePtr<Text>(); }
/**
* @brief
* @param text
* @return
*/
2026-02-11 19:40:26 +08:00
Ptr<Text> Text::create(const std::string &text) { return makePtr<Text>(text); }
/**
* @brief
* @param text
* @param font
* @return
*/
2026-02-11 19:40:26 +08:00
Ptr<Text> Text::create(const std::string &text, Ptr<FontAtlas> font) {
auto t = makePtr<Text>(text);
t->setFont(font);
return t;
}
/**
* @brief
* @param fmt
* @param ...
* @return
*/
2026-02-11 19:40:26 +08:00
Ptr<Text> Text::createFormat(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char buffer[256];
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
return makePtr<Text>(buffer);
}
/**
* @brief
* @param font
* @param fmt
* @param ...
* @return
*/
2026-02-11 19:40:26 +08:00
Ptr<Text> Text::createFormat(Ptr<FontAtlas> font, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char buffer[256];
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
auto t = makePtr<Text>(buffer);
t->setFont(font);
return t;
}
/**
* @brief
* @return
*/
Rect Text::boundingBox() const {
2026-02-11 19:40:26 +08:00
if (!font_ || text_.empty()) {
return Rect();
}
updateCache();
Vec2 size = cachedSize_;
if (size.x <= 0.0f || size.y <= 0.0f) {
return Rect();
}
Vec2 pos = calculateDrawPosition();
return Rect(pos.x, pos.y, size.x, size.y);
}
/**
* @brief
* @param renderer
*/
void Text::onDrawWidget(Renderer &renderer) {
2026-02-11 19:40:26 +08:00
if (!font_ || text_.empty()) {
return;
}
Vec2 pos = calculateDrawPosition();
renderer.drawText(*font_, text_, pos, color_);
}
} // namespace extra2d