mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-01-20 20:56:22 +00:00
UI: Allow TextViews to use wordwrap.
But they must have a fixed width.
This commit is contained in:
parent
30e99206c9
commit
a2494b4ff2
@ -335,14 +335,14 @@ void DrawBuffer::DrawImage2GridH(ImageID atlas_image, float x1, float y1, float
|
||||
class AtlasWordWrapper : public WordWrapper {
|
||||
public:
|
||||
// Note: maxW may be height if rotated.
|
||||
AtlasWordWrapper(AtlasFont &atlasfont, float scale, const char *str, float maxW) : WordWrapper(str, maxW), atlasfont_(atlasfont), scale_(scale) {
|
||||
AtlasWordWrapper(const AtlasFont &atlasfont, float scale, const char *str, float maxW) : WordWrapper(str, maxW), atlasfont_(atlasfont), scale_(scale) {
|
||||
}
|
||||
|
||||
protected:
|
||||
float MeasureWidth(const char *str, size_t bytes) override;
|
||||
|
||||
AtlasFont &atlasfont_;
|
||||
float scale_;
|
||||
const AtlasFont &atlasfont_;
|
||||
const float scale_;
|
||||
};
|
||||
|
||||
float AtlasWordWrapper::MeasureWidth(const char *str, size_t bytes) {
|
||||
@ -393,6 +393,16 @@ void DrawBuffer::MeasureTextCount(int font, const char *text, int count, float *
|
||||
if (h) *h = atlasfont.height * fontscaley * lines;
|
||||
}
|
||||
|
||||
void DrawBuffer::MeasureTextRect(int font, const char *text, int count, const Bounds &bounds, float *w, float *h, int align) {
|
||||
std::string toMeasure = std::string(text, count);
|
||||
if (align & FLAG_WRAP_TEXT) {
|
||||
AtlasWordWrapper wrapper(*atlas->fonts[font], fontscalex, toMeasure.c_str(), bounds.w);
|
||||
toMeasure = wrapper.Wrapped();
|
||||
}
|
||||
|
||||
MeasureTextCount(font, toMeasure.c_str(), (int)toMeasure.length(), w, h);
|
||||
}
|
||||
|
||||
void DrawBuffer::MeasureText(int font, const char *text, float *w, float *h) {
|
||||
return MeasureTextCount(font, text, (int)strlen(text), w, h);
|
||||
}
|
||||
@ -428,7 +438,12 @@ void DrawBuffer::DrawTextRect(int font, const char *text, float x, float y, floa
|
||||
y += h;
|
||||
}
|
||||
|
||||
DrawText(font, text, x, y, color, align);
|
||||
std::string toDraw = text;
|
||||
if (align & FLAG_WRAP_TEXT) {
|
||||
AtlasWordWrapper wrapper(*atlas->fonts[font], fontscalex, toDraw.c_str(), w);
|
||||
toDraw = wrapper.Wrapped();
|
||||
}
|
||||
DrawText(font, toDraw.c_str(), x, y, color, align);
|
||||
}
|
||||
|
||||
// ROTATE_* doesn't yet work right.
|
||||
|
@ -38,7 +38,8 @@ enum {
|
||||
// Avoids using system font drawing as it's too slow.
|
||||
// Not actually used here but is reserved for whatever system wraps DrawBuffer.
|
||||
FLAG_DYNAMIC_ASCII = 2048,
|
||||
FLAG_NO_PREFIX = 4096 // means to not process ampersands
|
||||
FLAG_NO_PREFIX = 4096, // means to not process ampersands
|
||||
FLAG_WRAP_TEXT = 8192,
|
||||
};
|
||||
|
||||
class Thin3DShaderSet;
|
||||
@ -126,7 +127,8 @@ public:
|
||||
|
||||
// NOTE: Count is in plain chars not utf-8 chars!
|
||||
void MeasureTextCount(int font, const char *text, int count, float *w, float *h);
|
||||
|
||||
void MeasureTextRect(int font, const char *text, int count, const Bounds &bounds, float *w, float *h, int align = 0);
|
||||
|
||||
void DrawTextRect(int font, const char *text, float x, float y, float w, float h, Color color = 0xFFFFFFFF, int align = 0);
|
||||
void DrawText(int font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0);
|
||||
void DrawTextShadow(int font, const char *text, float x, float y, Color color = 0xFFFFFFFF, int align = 0);
|
||||
|
@ -148,13 +148,42 @@ void TextDrawer::MeasureString(const char *str, size_t len, float *w, float *h)
|
||||
*h = size.cy * fontScaleY_;
|
||||
}
|
||||
|
||||
void TextDrawer::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) {
|
||||
auto iter = fontMap_.find(fontHash_);
|
||||
if (iter != fontMap_.end()) {
|
||||
SelectObject(ctx_->hDC, iter->second->hFont);
|
||||
}
|
||||
|
||||
std::string toMeasure = std::string(str, len);
|
||||
if (align & FLAG_WRAP_TEXT) {
|
||||
bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0;
|
||||
WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w);
|
||||
}
|
||||
|
||||
std::vector<std::string> lines;
|
||||
SplitString(toMeasure, '\n', lines);
|
||||
float total_w = 0.0f;
|
||||
float total_h = 0.0f;
|
||||
for (size_t i = 0; i < lines.size(); i++) {
|
||||
SIZE size;
|
||||
std::wstring wstr = ConvertUTF8ToWString(lines[i].length() == 0 ? " " : lines[i]);
|
||||
GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size);
|
||||
if (total_w < size.cx * fontScaleX_) {
|
||||
total_w = size.cx * fontScaleX_;
|
||||
}
|
||||
total_h += size.cy * fontScaleY_;
|
||||
}
|
||||
*w = total_w;
|
||||
*h = total_h;
|
||||
}
|
||||
|
||||
void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) {
|
||||
if (!strlen(str))
|
||||
return;
|
||||
|
||||
uint32_t stringHash = hash::Fletcher((const uint8_t *)str, strlen(str));
|
||||
uint32_t entryHash = stringHash ^ fontHash_;
|
||||
|
||||
|
||||
target.Flush(true);
|
||||
|
||||
TextStringEntry *entry;
|
||||
@ -288,6 +317,25 @@ void TextDrawer::MeasureString(const char *str, size_t len, float *w, float *h)
|
||||
#endif
|
||||
}
|
||||
|
||||
void TextDrawer::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) {
|
||||
std::string toMeasure = std::string(str, len);
|
||||
if (align & FLAG_WRAP_TEXT) {
|
||||
bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0;
|
||||
WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w);
|
||||
}
|
||||
|
||||
#ifdef USING_QT_UI
|
||||
QFont* font = fontMap_.find(fontHash_)->second;
|
||||
QFontMetrics fm(*font);
|
||||
QSize size = fm.size(0, QString::fromUtf8(toMeasure.c_str(), (int)toMeasure.size()));
|
||||
*w = (float)size.width() * fontScaleX_;
|
||||
*h = (float)size.height() * fontScaleY_;
|
||||
#else
|
||||
*w = 0;
|
||||
*h = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) {
|
||||
if (!strlen(str))
|
||||
return;
|
||||
@ -351,6 +399,11 @@ void TextDrawer::DrawString(DrawBuffer &target, const char *str, float x, float
|
||||
|
||||
#endif
|
||||
|
||||
void TextDrawer::WrapString(std::string &out, const char *str, float maxW) {
|
||||
TextDrawerWordWrapper wrapper(this, str, maxW);
|
||||
out = wrapper.Wrapped();
|
||||
}
|
||||
|
||||
void TextDrawer::SetFontScale(float xscale, float yscale) {
|
||||
fontScaleX_ = xscale;
|
||||
fontScaleY_ = xscale;
|
||||
@ -370,7 +423,13 @@ void TextDrawer::DrawStringRect(DrawBuffer &target, const char *str, const Bound
|
||||
y = bounds.y2();
|
||||
}
|
||||
|
||||
DrawString(target, str, x, y, color, align);
|
||||
std::string toDraw = str;
|
||||
if (align & FLAG_WRAP_TEXT) {
|
||||
bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0;
|
||||
WrapString(toDraw, str, rotated ? bounds.h : bounds.w);
|
||||
}
|
||||
|
||||
DrawString(target, toDraw.c_str(), x, y, color, align);
|
||||
}
|
||||
|
||||
void TextDrawer::OncePerFrame() {
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
void SetFontScale(float xscale, float yscale);
|
||||
void MeasureString(const char *str, float *w, float *h);
|
||||
void MeasureString(const char *str, size_t len, float *w, float *h);
|
||||
void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT);
|
||||
void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT);
|
||||
void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align);
|
||||
// Use for housekeeping like throwing out old strings.
|
||||
@ -58,6 +59,8 @@ public:
|
||||
private:
|
||||
Thin3DContext *thin3d_;
|
||||
|
||||
void WrapString(std::string &out, const char *str, float maxWidth);
|
||||
|
||||
int frameCount_;
|
||||
float fontScaleX_;
|
||||
float fontScaleY_;
|
||||
|
@ -138,8 +138,23 @@ void UIContext::MeasureTextCount(const UI::FontStyle &style, const char *str, in
|
||||
Draw()->MeasureTextCount(style.atlasFont, str, count, x, y);
|
||||
} else {
|
||||
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
|
||||
std::string subset(str, count);
|
||||
textDrawer_->MeasureString(subset.c_str(), x, y);
|
||||
textDrawer_->MeasureString(str, count, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void UIContext::MeasureTextRect(const UI::FontStyle &style, const char *str, int count, const Bounds &bounds, float *x, float *y, int align) const {
|
||||
if ((align & FLAG_WRAP_TEXT) == 0) {
|
||||
MeasureTextCount(style, str, count, x, y, align);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) {
|
||||
float sizeFactor = (float)style.sizePts / 24.0f;
|
||||
Draw()->SetFontScale(fontScaleX_ * sizeFactor, fontScaleY_ * sizeFactor);
|
||||
Draw()->MeasureTextRect(style.atlasFont, str, count, bounds, x, y, align);
|
||||
} else {
|
||||
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
|
||||
textDrawer_->MeasureStringRect(str, count, bounds, x, y, align);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ public:
|
||||
void SetFontScale(float scaleX, float scaleY);
|
||||
void MeasureTextCount(const UI::FontStyle &style, const char *str, int count, float *x, float *y, int align = 0) const;
|
||||
void MeasureText(const UI::FontStyle &style, const char *str, float *x, float *y, int align = 0) const;
|
||||
void MeasureTextRect(const UI::FontStyle &style, const char *str, int count, const Bounds &bounds, float *x, float *y, int align = 0) const;
|
||||
void DrawText(const char *str, float x, float y, uint32_t color, int align = 0);
|
||||
void DrawTextShadow(const char *str, float x, float y, uint32_t color, int align = 0);
|
||||
void DrawTextRect(const char *str, const Bounds &bounds, uint32_t color, int align = 0);
|
||||
|
@ -630,20 +630,9 @@ void Thin3DTextureView::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
void TextView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
// MeasureText doesn't seem to work with line breaks, so do something more sophisticated.
|
||||
std::vector<std::string> lines;
|
||||
SplitString(text_, '\n', lines);
|
||||
float total_w = 0.f;
|
||||
float total_h = 0.f;
|
||||
for (size_t i = 0; i < lines.size(); i++) {
|
||||
float temp_w, temp_h;
|
||||
dc.MeasureText(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont, lines[i].c_str(), &temp_w, &temp_h);
|
||||
if (temp_w > total_w)
|
||||
total_w = temp_w;
|
||||
total_h += temp_h;
|
||||
}
|
||||
w = total_w;
|
||||
h = total_h;
|
||||
// We don't have the bounding w/h yet, so stick with hardset layout params.
|
||||
Bounds bounds(0, 0, layoutParams_->width, layoutParams_->height);
|
||||
dc.MeasureTextRect(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont, text_.c_str(), (int)text_.length(), bounds, &w, &h, textAlign_);
|
||||
}
|
||||
|
||||
void TextView::Draw(UIContext &dc) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user