Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap text in many places where it makes sense #8900

Merged
merged 10 commits into from
Aug 8, 2016
103 changes: 74 additions & 29 deletions UI/GameScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ GameScreen::~GameScreen() {

void GameScreen::CreateViews() {
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
g_gameInfoCache->WaitUntilDone(info);

I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
Expand All @@ -67,18 +66,31 @@ void GameScreen::CreateViews() {
leftColumn->Add(new Choice(di->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &GameScreen::OnSwitchBack);
if (info) {
texvGameIcon_ = leftColumn->Add(new Thin3DTextureView(0, IS_DEFAULT, new AnchorLayoutParams(144 * 2, 80 * 2, 10, 10, NONE, NONE)));
tvTitle_ = leftColumn->Add(new TextView(info->GetTitle(), ALIGN_LEFT, false, new AnchorLayoutParams(10, 200, NONE, NONE)));

LinearLayout *infoLayout = new LinearLayout(ORIENT_VERTICAL, new AnchorLayoutParams(10, 200, NONE, NONE));
leftColumn->Add(infoLayout);

tvTitle_ = infoLayout->Add(new TextView(info->GetTitle(), ALIGN_LEFT | FLAG_WRAP_TEXT, false, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
tvTitle_->SetShadow(true);
infoLayout->Add(new Spacer(12));
// This one doesn't need to be updated.
leftColumn->Add(new TextView(gamePath_, ALIGN_LEFT, true, new AnchorLayoutParams(10, 250, NONE, NONE)))->SetShadow(true);
tvGameSize_ = leftColumn->Add(new TextView("...", ALIGN_LEFT, true, new AnchorLayoutParams(10, 290, NONE, NONE)));
infoLayout->Add(new TextView(gamePath_, ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)))->SetShadow(true);
tvGameSize_ = infoLayout->Add(new TextView("...", ALIGN_LEFT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
tvGameSize_->SetShadow(true);
tvSaveDataSize_ = leftColumn->Add(new TextView("...", ALIGN_LEFT, true, new AnchorLayoutParams(10, 320, NONE, NONE)));
tvSaveDataSize_ = infoLayout->Add(new TextView("...", ALIGN_LEFT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
tvSaveDataSize_->SetShadow(true);
tvInstallDataSize_ = leftColumn->Add(new TextView("", ALIGN_LEFT, true, new AnchorLayoutParams(10, 350, NONE, NONE)));
tvInstallDataSize_ = infoLayout->Add(new TextView("", ALIGN_LEFT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
tvInstallDataSize_->SetShadow(true);
tvRegion_ = leftColumn->Add(new TextView("", ALIGN_LEFT, true, new AnchorLayoutParams(10, 380, NONE, NONE)));
tvInstallDataSize_->SetVisibility(V_GONE);
tvRegion_ = infoLayout->Add(new TextView("", ALIGN_LEFT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
tvRegion_->SetShadow(true);
} else {
texvGameIcon_ = nullptr;
tvTitle_ = nullptr;
tvGameSize_ = nullptr;
tvSaveDataSize_ = nullptr;
tvInstallDataSize_ = nullptr;
tvRegion_ = nullptr;
}

ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins));
Expand All @@ -87,39 +99,54 @@ void GameScreen::CreateViews() {
LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL);
rightColumnItems->SetSpacing(0.0f);
rightColumn->Add(rightColumnItems);
Choice *play = new Choice(ga->T("Play"));
rightColumnItems->Add(play)->OnClick.Handle(this, &GameScreen::OnPlay);
if (info && !info->id.empty())
{
if (info->hasConfig)
{
rightColumnItems->Add(new Choice(ga->T("Game Settings")))->OnClick.Handle(this, &GameScreen::OnGameSettings);
rightColumnItems->Add(new Choice(ga->T("Delete Game Config")))->OnClick.Handle(this, &GameScreen::OnDeleteConfig);
}
else
{
rightColumnItems->Add(new Choice(ga->T("Create Game Config")))->OnClick.Handle(this, &GameScreen::OnCreateConfig);
}
}
std::vector<std::string> saveDirs = info->GetSaveDataDirectories();
if (saveDirs.size()) {
rightColumnItems->Add(new Choice(ga->T("Delete Save Data")))->OnClick.Handle(this, &GameScreen::OnDeleteSaveData);

rightColumnItems->Add(new Choice(ga->T("Play")))->OnClick.Handle(this, &GameScreen::OnPlay);

if (info) {
btnGameSettings_ = rightColumnItems->Add(new Choice(ga->T("Game Settings")));
btnGameSettings_->OnClick.Handle(this, &GameScreen::OnGameSettings);
btnDeleteGameConfig_ = rightColumnItems->Add(new Choice(ga->T("Delete Game Config")));
btnDeleteGameConfig_->OnClick.Handle(this, &GameScreen::OnDeleteConfig);
btnCreateGameConfig_ = rightColumnItems->Add(new Choice(ga->T("Create Game Config")));
btnCreateGameConfig_->OnClick.Handle(this, &GameScreen::OnCreateConfig);

btnGameSettings_->SetVisibility(V_GONE);
btnDeleteGameConfig_->SetVisibility(V_GONE);
btnCreateGameConfig_->SetVisibility(V_GONE);

btnDeleteSaveData_ = new Choice(ga->T("Delete Save Data"));
rightColumnItems->Add(btnDeleteSaveData_)->OnClick.Handle(this, &GameScreen::OnDeleteSaveData);
btnDeleteSaveData_->SetVisibility(V_GONE);
} else {
btnGameSettings_ = nullptr;
btnCreateGameConfig_ = nullptr;
btnDeleteGameConfig_ = nullptr;
btnDeleteSaveData_ = nullptr;
}
rightColumnItems->Add(new Choice(ga->T("Delete Game")))->OnClick.Handle(this, &GameScreen::OnDeleteGame);


rightColumnItems->Add(AddOtherChoice(new Choice(ga->T("Delete Game"))))->OnClick.Handle(this, &GameScreen::OnDeleteGame);
if (host->CanCreateShortcut()) {
rightColumnItems->Add(new Choice(ga->T("Create Shortcut")))->OnClick.Handle(this, &GameScreen::OnCreateShortcut);
rightColumnItems->Add(AddOtherChoice(new Choice(ga->T("Create Shortcut"))))->OnClick.Handle(this, &GameScreen::OnCreateShortcut);
}
if (isRecentGame(gamePath_)) {
rightColumnItems->Add(new Choice(ga->T("Remove From Recent")))->OnClick.Handle(this, &GameScreen::OnRemoveFromRecent);
rightColumnItems->Add(AddOtherChoice(new Choice(ga->T("Remove From Recent"))))->OnClick.Handle(this, &GameScreen::OnRemoveFromRecent);
}
#ifdef _WIN32
rightColumnItems->Add(new Choice(ga->T("Show In Folder")))->OnClick.Handle(this, &GameScreen::OnShowInFolder);
rightColumnItems->Add(AddOtherChoice(new Choice(ga->T("Show In Folder"))))->OnClick.Handle(this, &GameScreen::OnShowInFolder);
#endif
if (g_Config.bEnableCheats) {
rightColumnItems->Add(new Choice(pa->T("Cheats")))->OnClick.Handle(this, &GameScreen::OnCwCheat);
rightColumnItems->Add(AddOtherChoice(new Choice(pa->T("Cheats"))))->OnClick.Handle(this, &GameScreen::OnCwCheat);
}
}

UI::Choice *GameScreen::AddOtherChoice(UI::Choice *choice) {
otherChoices_.push_back(choice);
// While loading.
choice->SetVisibility(UI::V_GONE);
return choice;
}

UI::EventReturn GameScreen::OnCreateConfig(UI::EventParams &e)
{
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_,0);
Expand Down Expand Up @@ -187,6 +214,7 @@ void GameScreen::update(InputState &input) {
if (info->installDataSize > 0) {
sprintf(temp, "%s: %1.2f %s", ga->T("InstallData"), (float) (info->installDataSize) / 1024.f / 1024.f, ga->T("MB"));
tvInstallDataSize_->SetText(temp);
tvInstallDataSize_->SetVisibility(UI::V_VISIBLE);
}
}

Expand All @@ -200,6 +228,23 @@ void GameScreen::update(InputState &input) {
};
tvRegion_->SetText(ga->T(regionNames[info->region]));
}

if (!info->id.empty()) {
btnGameSettings_->SetVisibility(info->hasConfig ? UI::V_VISIBLE : UI::V_GONE);
btnDeleteGameConfig_->SetVisibility(info->hasConfig ? UI::V_VISIBLE : UI::V_GONE);
btnCreateGameConfig_->SetVisibility(info->hasConfig ? UI::V_GONE : UI::V_VISIBLE);

std::vector<std::string> saveDirs = info->GetSaveDataDirectories();
if (saveDirs.size()) {
btnDeleteSaveData_->SetVisibility(UI::V_VISIBLE);
}
}
if (!info->IsPending()) {
// At this point, the above buttons won't become visible. We can show these now.
for (UI::Choice *choice : otherChoices_) {
choice->SetVisibility(UI::V_VISIBLE);
}
}
}

UI::EventReturn GameScreen::OnShowInFolder(UI::EventParams &e) {
Expand Down
8 changes: 8 additions & 0 deletions UI/GameScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class GameScreen : public UIDialogScreenWithGameBackground {
bool isRecentGame(const std::string &gamePath);

private:
UI::Choice *AddOtherChoice(UI::Choice *choice);

// Event handlers
UI::EventReturn OnPlay(UI::EventParams &e);
UI::EventReturn OnGameSettings(UI::EventParams &e);
Expand All @@ -64,4 +66,10 @@ class GameScreen : public UIDialogScreenWithGameBackground {
UI::TextView *tvSaveDataSize_;
UI::TextView *tvInstallDataSize_;
UI::TextView *tvRegion_;

UI::Choice *btnGameSettings_;
UI::Choice *btnCreateGameConfig_;
UI::Choice *btnDeleteGameConfig_;
UI::Choice *btnDeleteSaveData_;
std::vector<UI::Choice *> otherChoices_;
};
13 changes: 6 additions & 7 deletions UI/MainScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ void GameButton::Draw(UIContext &dc) {
title_ = ReplaceAll(title_, "\n", " ");
}

dc.MeasureText(dc.GetFontStyle(), title_.c_str(), &tw, &th, 0);
dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, title_.c_str(), &tw, &th, 0);

int availableWidth = bounds_.w - 150;
float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f;
Expand Down Expand Up @@ -367,7 +367,7 @@ void DirButton::Draw(UIContext &dc) {
}

float tw, th;
dc.MeasureText(dc.GetFontStyle(), text.c_str(), &tw, &th, 0);
dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text.c_str(), &tw, &th, 0);

bool compact = bounds_.w < 180;

Expand Down Expand Up @@ -484,15 +484,14 @@ void GameBrowser::Refresh() {
LinearLayout *topBar = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT));
if (allowBrowsing_) {
topBar->Add(new Spacer(2.0f));
Margins pathMargins(5, 0);
topBar->Add(new TextView(path_.GetFriendlyPath().c_str(), ALIGN_VCENTER, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, 1.0f)));
topBar->Add(new TextView(path_.GetFriendlyPath().c_str(), ALIGN_VCENTER | FLAG_WRAP_TEXT, true, new LinearLayoutParams(FILL_PARENT, 64.0f, 1.0f)));
#if defined(_WIN32) || defined(USING_QT_UI)
topBar->Add(new Choice(mm->T("Browse", "Browse...")))->OnClick.Handle(this, &GameBrowser::HomeClick);
topBar->Add(new Choice(mm->T("Browse", "Browse..."), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::HomeClick);
#else
topBar->Add(new Choice(mm->T("Home")))->OnClick.Handle(this, &GameBrowser::HomeClick);
topBar->Add(new Choice(mm->T("Home"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::HomeClick);
#endif
} else {
topBar->Add(new Spacer(new LinearLayoutParams(1.0f)));
topBar->Add(new Spacer(new LinearLayoutParams(FILL_PARENT, 64.0f, 1.0f)));
}

ChoiceStrip *layoutChoice = topBar->Add(new ChoiceStrip(ORIENT_HORIZONTAL));
Expand Down
4 changes: 2 additions & 2 deletions UI/OnScreenDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) {

// Get height
float w, h;
dc.MeasureText(dc.theme->uiFont, "Wg", &w, &h);
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, "Wg", &w, &h);

float y = 10.0f;
// Then draw them all.
Expand All @@ -27,7 +27,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
if (alpha < 0.0) alpha = 0.0f;
// Messages that are wider than the screen are left-aligned instead of centered.
float tw, th;
dc.MeasureText(dc.theme->uiFont, iter->text.c_str(), &tw, &th);
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, iter->text.c_str(), &tw, &th);
float x = bounds_.centerX();
int align = ALIGN_TOP | ALIGN_HCENTER;
if (tw > bounds_.w) {
Expand Down
32 changes: 20 additions & 12 deletions UI/SavedataScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,28 @@ std::string GetFileDateAsString(std::string filename) {
return "";
}

static std::string TrimString(const std::string &str) {
size_t pos = str.find_last_not_of(" \r\n\t");
if (pos != str.npos) {
return str.substr(0, pos + 1);
}
return str;
}

class SavedataPopupScreen : public PopupScreen {
public:
SavedataPopupScreen(std::string savePath, std::string title) : PopupScreen(title), savePath_(savePath) {
SavedataPopupScreen(std::string savePath, std::string title) : PopupScreen(TrimString(title)), savePath_(savePath) {
}

void CreatePopupContents(UI::ViewGroup *parent) override {
using namespace UI;
GameInfo *ginfo = g_gameInfoCache->GetInfo(screenManager()->getThin3DContext(), savePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
LinearLayout *root = new LinearLayout(ORIENT_VERTICAL);
parent->Add(root);
LinearLayout *content = new LinearLayout(ORIENT_VERTICAL);
parent->Add(content);
if (!ginfo)
return;
LinearLayout *toprow = new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
root->Add(toprow);
content->Add(toprow);

I18NCategory *sa = GetI18NCategory("Savedata");
if (ginfo->fileType == FILETYPE_PSP_SAVEDATA_DIRECTORY) {
Expand All @@ -74,15 +82,15 @@ class SavedataPopupScreen : public PopupScreen {
if (ginfo->iconTexture) {
toprow->Add(new Thin3DTextureView(ginfo->iconTexture, IS_FIXED, new LinearLayoutParams(Margins(10, 5))));
}
LinearLayout *topright = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0));
LinearLayout *topright = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f));
topright->SetSpacing(1.0f);
topright->Add(new TextView(savedata_title, 0, false));
topright->Add(new TextView(savedata_title, ALIGN_LEFT | FLAG_WRAP_TEXT, false));
topright->Add(new TextView(StringFromFormat("%d kB", ginfo->gameSize / 1024), 0, true));
topright->Add(new TextView(GetFileDateAsString(savePath_ + "/PARAM.SFO"), 0, true));
toprow->Add(topright);
root->Add(new Spacer(3.0));
root->Add(new TextView(savedata_detail, 0, true, new LinearLayoutParams(Margins(10, 0))));
root->Add(new Spacer(3.0));
content->Add(new Spacer(3.0));
content->Add(new TextView(ReplaceAll(savedata_detail, "\r", ""), ALIGN_LEFT | FLAG_WRAP_TEXT, true, new LinearLayoutParams(Margins(10, 0))));
content->Add(new Spacer(3.0));
} else {
std::string image_path = ReplaceAll(savePath_, ".ppst", ".jpg");
if (File::Exists(image_path)) {
Expand All @@ -91,14 +99,14 @@ class SavedataPopupScreen : public PopupScreen {
} else {
toprow->Add(new TextView(sa->T("No screenshot"), new LinearLayoutParams(Margins(10, 5))));
}
root->Add(new TextView(GetFileDateAsString(savePath_), 0, true, new LinearLayoutParams(Margins(10, 5))));
content->Add(new TextView(GetFileDateAsString(savePath_), 0, true, new LinearLayoutParams(Margins(10, 5))));
}

I18NCategory *di = GetI18NCategory("Dialog");
LinearLayout *buttons = new LinearLayout(ORIENT_HORIZONTAL);
buttons->Add(new Button(di->T("Back"), new LinearLayoutParams(1.0)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
buttons->Add(new Button(di->T("Delete"), new LinearLayoutParams(1.0)))->OnClick.Handle(this, &SavedataPopupScreen::OnDeleteButtonClick);
root->Add(buttons);
content->Add(buttons);
}

protected:
Expand Down Expand Up @@ -243,7 +251,7 @@ void SavedataButton::Draw(UIContext &dc) {
subtitle_ = CleanSaveString(savedata_title) + StringFromFormat(" (%d kB)", ginfo->gameSize / 1024);
}

dc.MeasureText(dc.GetFontStyle(), title_.c_str(), &tw, &th, 0);
dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, title_.c_str(), &tw, &th, 0);

int availableWidth = bounds_.w - 150;
float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f;
Expand Down
21 changes: 8 additions & 13 deletions ext/native/ui/ui_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,36 +127,31 @@ void UIContext::SetFontStyle(const UI::FontStyle &fontStyle) {
}
}

void UIContext::MeasureText(const UI::FontStyle &style, const char *str, float *x, float *y, int align) const {
MeasureTextCount(style, str, (int)strlen(str), x, y, align);
void UIContext::MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, float *x, float *y, int align) const {
MeasureTextCount(style, scaleX, scaleY, str, (int)strlen(str), x, y, align);
}

void UIContext::MeasureTextCount(const UI::FontStyle &style, const char *str, int count, float *x, float *y, int align) const {
void UIContext::MeasureTextCount(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, float *x, float *y, int align) const {
if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) {
float sizeFactor = (float)style.sizePts / 24.0f;
Draw()->SetFontScale(fontScaleX_ * sizeFactor, fontScaleY_ * sizeFactor);
Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor);
Draw()->MeasureTextCount(style.atlasFont, str, count, x, y);
} else {
textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags);
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
textDrawer_->SetFontScale(scaleX, scaleY);
textDrawer_->MeasureString(str, count, x, y);
textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags);
}
}

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;
}

void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, const Bounds &bounds, float *x, float *y, int align) const {
if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) {
float sizeFactor = (float)style.sizePts / 24.0f;
Draw()->SetFontScale(fontScaleX_ * sizeFactor, fontScaleY_ * sizeFactor);
Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor);
Draw()->MeasureTextRect(style.atlasFont, str, count, bounds, x, y, align);
} else {
textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags);
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
textDrawer_->SetFontScale(scaleX, scaleY);
textDrawer_->MeasureStringRect(str, count, bounds, x, y, align);
textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags);
}
Expand Down
6 changes: 3 additions & 3 deletions ext/native/ui/ui_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ class UIContext {
void SetFontStyle(const UI::FontStyle &style);
const UI::FontStyle &GetFontStyle() { return *fontStyle_; }
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 MeasureTextCount(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, int count, float *x, float *y, int align = 0) const;
void MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, const char *str, float *x, float *y, int align = 0) const;
void MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, 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);
Expand Down
Loading