mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-24 19:59:08 +02:00
Merge pull request #8900 from unknownbrackets/ui-text-wrap
Wrap text in many places where it makes sense
This commit is contained in:
commit
0924dbfdee
11 files changed
+296
-153
No files matched your search
+74
-29
@@ -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");
|
||||
@@ -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));
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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("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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -44,6 +44,8 @@ protected:
|
||||
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);
|
||||
@@ -64,4 +66,10 @@ private:
|
||||
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_;
|
||||
};
|
||||
+6
-7
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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.
|
||||
@@ -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) {
|
||||
|
||||
+20
-12
@@ -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) {
|
||||
@@ -74,15 +82,15 @@ public:
|
||||
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)) {
|
||||
@@ -91,14 +99,14 @@ public:
|
||||
} 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:
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ public:
|
||||
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);
|
||||
|
||||
@@ -313,6 +313,14 @@ UI::EventReturn ListPopupScreen::OnListChoice(UI::EventParams &e) {
|
||||
|
||||
namespace UI {
|
||||
|
||||
std::string ChopTitle(const std::string &title) {
|
||||
size_t pos = title.find('\n');
|
||||
if (pos != title.npos) {
|
||||
return title.substr(0, pos);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
UI::EventReturn PopupMultiChoice::HandleClick(UI::EventParams &e) {
|
||||
restoreFocus_ = HasFocus();
|
||||
|
||||
@@ -323,7 +331,7 @@ UI::EventReturn PopupMultiChoice::HandleClick(UI::EventParams &e) {
|
||||
choices.push_back(category ? category->T(choices_[i]) : choices_[i]);
|
||||
}
|
||||
|
||||
ListPopupScreen *popupScreen = new ListPopupScreen(text_, choices, *value_ - minVal_,
|
||||
ListPopupScreen *popupScreen = new ListPopupScreen(ChopTitle(text_), choices, *value_ - minVal_,
|
||||
std::bind(&PopupMultiChoice::ChoiceCallback, this, placeholder::_1));
|
||||
popupScreen->SetHiddenChoices(hidden_);
|
||||
screenManager_->push(popupScreen);
|
||||
@@ -369,7 +377,7 @@ void PopupMultiChoice::Draw(UIContext &dc) {
|
||||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
|
||||
float ignore;
|
||||
dc.MeasureText(dc.theme->uiFont, valueText_.c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, valueText_.c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
textPadding_.right += paddingX;
|
||||
|
||||
Choice::Draw(dc);
|
||||
@@ -403,7 +411,7 @@ PopupSliderChoiceFloat::PopupSliderChoiceFloat(float *value, float minValue, flo
|
||||
EventReturn PopupSliderChoice::HandleClick(EventParams &e) {
|
||||
restoreFocus_ = HasFocus();
|
||||
|
||||
SliderPopupScreen *popupScreen = new SliderPopupScreen(value_, minValue_, maxValue_, text_, step_, units_);
|
||||
SliderPopupScreen *popupScreen = new SliderPopupScreen(value_, minValue_, maxValue_, ChopTitle(text_), step_, units_);
|
||||
popupScreen->OnChange.Handle(this, &PopupSliderChoice::HandleChange);
|
||||
screenManager_->push(popupScreen);
|
||||
return EVENT_DONE;
|
||||
@@ -435,7 +443,7 @@ void PopupSliderChoice::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
float ignore;
|
||||
dc.MeasureText(dc.theme->uiFont, temp, &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, temp, &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
textPadding_.right += paddingX;
|
||||
|
||||
Choice::Draw(dc);
|
||||
@@ -445,7 +453,7 @@ void PopupSliderChoice::Draw(UIContext &dc) {
|
||||
EventReturn PopupSliderChoiceFloat::HandleClick(EventParams &e) {
|
||||
restoreFocus_ = HasFocus();
|
||||
|
||||
SliderFloatPopupScreen *popupScreen = new SliderFloatPopupScreen(value_, minValue_, maxValue_, text_, step_, units_);
|
||||
SliderFloatPopupScreen *popupScreen = new SliderFloatPopupScreen(value_, minValue_, maxValue_, ChopTitle(text_), step_, units_);
|
||||
popupScreen->OnChange.Handle(this, &PopupSliderChoiceFloat::HandleChange);
|
||||
screenManager_->push(popupScreen);
|
||||
return EVENT_DONE;
|
||||
@@ -477,7 +485,7 @@ void PopupSliderChoiceFloat::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
float ignore;
|
||||
dc.MeasureText(dc.theme->uiFont, temp, &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, temp, &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
textPadding_.right += paddingX;
|
||||
|
||||
Choice::Draw(dc);
|
||||
@@ -652,7 +660,7 @@ PopupTextInputChoice::PopupTextInputChoice(std::string *value, const std::string
|
||||
EventReturn PopupTextInputChoice::HandleClick(EventParams &e) {
|
||||
restoreFocus_ = HasFocus();
|
||||
|
||||
TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, text_, maxLen_);
|
||||
TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_);
|
||||
popupScreen->OnChange.Handle(this, &PopupTextInputChoice::HandleChange);
|
||||
screenManager_->push(popupScreen);
|
||||
return EVENT_DONE;
|
||||
@@ -667,7 +675,7 @@ void PopupTextInputChoice::Draw(UIContext &dc) {
|
||||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
|
||||
float ignore;
|
||||
dc.MeasureText(dc.theme->uiFont, value_->c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, value_->c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
textPadding_.right += paddingX;
|
||||
|
||||
Choice::Draw(dc);
|
||||
@@ -726,7 +734,7 @@ void ChoiceWithValueDisplay::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
float ignore;
|
||||
dc.MeasureText(dc.theme->uiFont, valueText.str().c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, valueText.str().c_str(), &textPadding_.right, &ignore, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
textPadding_.right += paddingX;
|
||||
|
||||
Choice::Draw(dc);
|
||||
|
||||
+105
-37
@@ -24,7 +24,7 @@ static recursive_mutex mutex_;
|
||||
|
||||
const float ITEM_HEIGHT = 64.f;
|
||||
const float MIN_TEXT_SCALE = 0.8f;
|
||||
|
||||
const float MAX_ITEM_SIZE = 65535.0f;
|
||||
|
||||
struct DispatchQueueItem {
|
||||
Event *e;
|
||||
@@ -102,9 +102,10 @@ void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measure
|
||||
*measured = contentWidth < spec.size ? contentWidth : spec.size;
|
||||
else if (spec.type == EXACTLY)
|
||||
*measured = spec.size;
|
||||
} else if (sz == FILL_PARENT) {
|
||||
} else if (sz == FILL_PARENT) {
|
||||
// UNSPECIFIED may have a minimum size of the parent. Let's use it to fill.
|
||||
if (spec.type == UNSPECIFIED)
|
||||
*measured = contentWidth; // We have no value to set
|
||||
*measured = std::max(spec.size, contentWidth);
|
||||
else
|
||||
*measured = spec.size;
|
||||
} else if (spec.type == EXACTLY || (spec.type == AT_MOST && *measured > spec.size)) {
|
||||
@@ -112,6 +113,24 @@ void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measure
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyBoundBySpec(float &bound, MeasureSpec spec) {
|
||||
switch (spec.type) {
|
||||
case AT_MOST:
|
||||
bound = bound < spec.size ? bound : spec.size;
|
||||
break;
|
||||
case EXACTLY:
|
||||
bound = spec.size;
|
||||
break;
|
||||
case UNSPECIFIED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyBoundsBySpec(Bounds &bounds, MeasureSpec horiz, MeasureSpec vert) {
|
||||
ApplyBoundBySpec(bounds.w, horiz);
|
||||
ApplyBoundBySpec(bounds.h, vert);
|
||||
}
|
||||
|
||||
void Event::Add(std::function<EventReturn(EventParams&)> func) {
|
||||
HandlerRegistration reg;
|
||||
reg.func = func;
|
||||
@@ -142,7 +161,7 @@ View::~View() {
|
||||
|
||||
void View::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) {
|
||||
float contentW = 0.0f, contentH = 0.0f;
|
||||
GetContentDimensions(dc, contentW, contentH);
|
||||
GetContentDimensionsBySpec(dc, horiz, vert, contentW, contentH);
|
||||
MeasureBySpec(layoutParams_->width, contentW, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, contentH, vert, &measuredHeight_);
|
||||
}
|
||||
@@ -154,6 +173,10 @@ void View::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
h = 10.0f;
|
||||
}
|
||||
|
||||
void View::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const {
|
||||
GetContentDimensions(dc, w, h);
|
||||
}
|
||||
|
||||
void View::Query(float x, float y, std::vector<View *> &list) {
|
||||
if (bounds_.Contains(x, y)) {
|
||||
list.push_back(this);
|
||||
@@ -390,14 +413,13 @@ void Item::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
|
||||
void ClickableItem::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
w = 0.0f;
|
||||
h = 0.0f;
|
||||
h = ITEM_HEIGHT;
|
||||
}
|
||||
|
||||
ClickableItem::ClickableItem(LayoutParams *layoutParams) : Clickable(layoutParams) {
|
||||
if (!layoutParams) {
|
||||
if (layoutParams_->width == WRAP_CONTENT)
|
||||
layoutParams_->width = FILL_PARENT;
|
||||
layoutParams_->height = ITEM_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,16 +436,35 @@ void ClickableItem::Draw(UIContext &dc) {
|
||||
dc.FillRect(style.background, bounds_);
|
||||
}
|
||||
|
||||
void Choice::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
void Choice::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const {
|
||||
if (atlasImage_ != -1) {
|
||||
const AtlasImage &img = dc.Draw()->GetAtlas()->images[atlasImage_];
|
||||
w = img.w;
|
||||
h = img.h;
|
||||
} else {
|
||||
dc.MeasureText(dc.theme->uiFont, text_.c_str(), &w, &h);
|
||||
const int paddingX = 12;
|
||||
float availWidth = horiz.size - paddingX * 2 - textPadding_.horiz();
|
||||
if (availWidth < 0.0f) {
|
||||
// Let it have as much space as it needs.
|
||||
availWidth = MAX_ITEM_SIZE;
|
||||
}
|
||||
float scale = CalculateTextScale(dc, availWidth);
|
||||
Bounds availBounds(0, 0, availWidth, vert.size);
|
||||
dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &w, &h, FLAG_WRAP_TEXT);
|
||||
}
|
||||
w += 24;
|
||||
h += 16;
|
||||
h = std::max(h, ITEM_HEIGHT);
|
||||
}
|
||||
|
||||
float Choice::CalculateTextScale(const UIContext &dc, float availWidth) const {
|
||||
float actualWidth, actualHeight;
|
||||
Bounds availBounds(0, 0, availWidth, bounds_.h);
|
||||
dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight);
|
||||
if (actualWidth > availWidth) {
|
||||
return std::max(MIN_TEXT_SCALE, availWidth / actualWidth);
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void Choice::HighlightChanged(bool highlighted){
|
||||
@@ -459,23 +500,18 @@ void Choice::Draw(UIContext &dc) {
|
||||
|
||||
const int paddingX = 12;
|
||||
const float availWidth = bounds_.w - paddingX * 2 - textPadding_.horiz();
|
||||
float scale = 1.0f;
|
||||
|
||||
float actualWidth, actualHeight;
|
||||
dc.MeasureText(dc.theme->uiFont, text_.c_str(), &actualWidth, &actualHeight, ALIGN_VCENTER);
|
||||
if (actualWidth > availWidth) {
|
||||
scale = std::max(MIN_TEXT_SCALE, availWidth / actualWidth);
|
||||
}
|
||||
float scale = CalculateTextScale(dc, availWidth);
|
||||
|
||||
dc.SetFontScale(scale, scale);
|
||||
if (centered_) {
|
||||
dc.DrawText(text_.c_str(), bounds_.centerX(), bounds_.centerY(), style.fgColor, ALIGN_CENTER);
|
||||
dc.DrawTextRect(text_.c_str(), bounds_, style.fgColor, ALIGN_CENTER | FLAG_WRAP_TEXT);
|
||||
} else {
|
||||
if (iconImage_ != -1) {
|
||||
dc.Draw()->DrawImage(iconImage_, bounds_.x2() - 32 - paddingX, bounds_.centerY(), 0.5f, style.fgColor, ALIGN_CENTER);
|
||||
}
|
||||
|
||||
dc.DrawText(text_.c_str(), bounds_.x + paddingX + textPadding_.left, bounds_.centerY(), style.fgColor, ALIGN_VCENTER);
|
||||
Bounds textBounds(bounds_.x + paddingX + textPadding_.left, bounds_.y, availWidth, bounds_.h);
|
||||
dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT);
|
||||
}
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
@@ -518,7 +554,7 @@ void PopupHeader::Draw(UIContext &dc) {
|
||||
|
||||
float tw, th;
|
||||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
dc.MeasureText(dc.GetFontStyle(), text_.c_str(), &tw, &th, 0);
|
||||
dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text_.c_str(), &tw, &th, 0);
|
||||
|
||||
float sineWidth = std::max(0.0f, (tw - availableWidth)) / 2.0f;
|
||||
|
||||
@@ -565,27 +601,54 @@ void CheckBox::Draw(UIContext &dc) {
|
||||
const int paddingX = 12;
|
||||
// Padding right of the checkbox image too.
|
||||
const float availWidth = bounds_.w - paddingX * 2 - imageW - paddingX;
|
||||
float scale = 1.0f;
|
||||
|
||||
float actualWidth, actualHeight;
|
||||
dc.MeasureText(dc.theme->uiFont, text_.c_str(), &actualWidth, &actualHeight, ALIGN_VCENTER);
|
||||
if (actualWidth > availWidth) {
|
||||
scale = std::max(MIN_TEXT_SCALE, availWidth / actualWidth);
|
||||
}
|
||||
float scale = CalculateTextScale(dc, availWidth);
|
||||
|
||||
dc.SetFontScale(scale, scale);
|
||||
dc.DrawText(text_.c_str(), bounds_.x + paddingX, bounds_.centerY(), style.fgColor, ALIGN_VCENTER);
|
||||
Bounds textBounds(bounds_.x + paddingX, bounds_.y, availWidth, bounds_.h);
|
||||
dc.DrawTextRect(text_.c_str(), textBounds, style.fgColor, ALIGN_VCENTER | FLAG_WRAP_TEXT);
|
||||
dc.Draw()->DrawImage(image, bounds_.x2() - paddingX, bounds_.centerY(), 1.0f, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
float CheckBox::CalculateTextScale(const UIContext &dc, float availWidth) const {
|
||||
float actualWidth, actualHeight;
|
||||
Bounds availBounds(0, 0, availWidth, bounds_.h);
|
||||
dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER);
|
||||
if (actualWidth > availWidth) {
|
||||
return std::max(MIN_TEXT_SCALE, availWidth / actualWidth);
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void CheckBox::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
int image = *toggle_ ? dc.theme->checkOn : dc.theme->checkOff;
|
||||
float imageW, imageH;
|
||||
dc.Draw()->MeasureImage(image, &imageW, &imageH);
|
||||
|
||||
const int paddingX = 12;
|
||||
// Padding right of the checkbox image too.
|
||||
float availWidth = bounds_.w - paddingX * 2 - imageW - paddingX;
|
||||
if (availWidth < 0.0f) {
|
||||
// Let it have as much space as it needs.
|
||||
availWidth = MAX_ITEM_SIZE;
|
||||
}
|
||||
float scale = CalculateTextScale(dc, availWidth);
|
||||
|
||||
float actualWidth, actualHeight;
|
||||
Bounds availBounds(0, 0, availWidth, bounds_.h);
|
||||
dc.MeasureTextRect(dc.theme->uiFont, scale, scale, text_.c_str(), (int)text_.size(), availBounds, &actualWidth, &actualHeight, ALIGN_VCENTER | FLAG_WRAP_TEXT);
|
||||
|
||||
w = bounds_.w;
|
||||
h = std::max(actualHeight, ITEM_HEIGHT);
|
||||
}
|
||||
|
||||
void Button::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
if (imageID_ != -1) {
|
||||
const AtlasImage *img = &dc.Draw()->GetAtlas()->images[imageID_];
|
||||
w = img->w;
|
||||
h = img->h;
|
||||
} else {
|
||||
dc.MeasureText(dc.theme->uiFont, text_.c_str(), &w, &h);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &w, &h);
|
||||
}
|
||||
// Add some internal padding to not look totally ugly
|
||||
w += 16;
|
||||
@@ -602,7 +665,7 @@ void Button::Draw(UIContext &dc) {
|
||||
// dc.Draw()->DrawImage4Grid(style.image, bounds_.x, bounds_.y, bounds_.x2(), bounds_.y2(), style.bgColor);
|
||||
dc.FillRect(style.background, bounds_);
|
||||
float tw, th;
|
||||
dc.MeasureText(dc.theme->uiFont, text_.c_str(), &tw, &th);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), &tw, &th);
|
||||
if (tw > bounds_.w || imageID_ != -1) {
|
||||
dc.PushScissor(bounds_);
|
||||
}
|
||||
@@ -657,17 +720,22 @@ void Thin3DTextureView::Draw(UIContext &dc) {
|
||||
}
|
||||
}
|
||||
|
||||
void TextView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
// We don't have the bounding w/h yet, so stick with hardset layout params.
|
||||
void TextView::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const {
|
||||
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_);
|
||||
if (bounds.w < 0) {
|
||||
// If there's no size, let's grow as big as we want.
|
||||
bounds.w = horiz.size == 0 ? MAX_ITEM_SIZE : horiz.size;
|
||||
}
|
||||
if (bounds.h < 0) {
|
||||
bounds.h = vert.size == 0 ? MAX_ITEM_SIZE : vert.size;
|
||||
}
|
||||
ApplyBoundsBySpec(bounds, horiz, vert);
|
||||
dc.MeasureTextRect(small_ ? dc.theme->uiFontSmall : dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), (int)text_.length(), bounds, &w, &h, textAlign_);
|
||||
}
|
||||
|
||||
void TextView::Draw(UIContext &dc) {
|
||||
float w, h;
|
||||
GetContentDimensions(dc, w, h);
|
||||
bool clip = false;
|
||||
if (w > bounds_.w || h > bounds_.h)
|
||||
if (measuredWidth_ > bounds_.w || measuredHeight_ > bounds_.h)
|
||||
clip = true;
|
||||
if (bounds_.w < 0 || bounds_.h < 0 || !clip_) {
|
||||
// We have a layout but, but try not to screw up rendering.
|
||||
@@ -721,7 +789,7 @@ void TextEdit::Draw(UIContext &dc) {
|
||||
|
||||
if (HasFocus()) {
|
||||
// Hack to find the caret position. Might want to find a better way...
|
||||
dc.MeasureTextCount(dc.theme->uiFont, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT);
|
||||
dc.MeasureTextCount(dc.theme->uiFont, 1.0f, 1.0f, text_.c_str(), caret_, &w, &h, ALIGN_VCENTER | ALIGN_LEFT);
|
||||
float caretX = w;
|
||||
caretX += textX;
|
||||
|
||||
@@ -735,7 +803,7 @@ void TextEdit::Draw(UIContext &dc) {
|
||||
}
|
||||
|
||||
void TextEdit::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
dc.MeasureText(dc.theme->uiFont, text_.size() ? text_.c_str() : "Wj", &w, &h);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text_.size() ? text_.c_str() : "Wj", &w, &h);
|
||||
w += 2;
|
||||
h += 2;
|
||||
}
|
||||
@@ -904,7 +972,7 @@ void TextEdit::InsertAtCaret(const char *text) {
|
||||
}
|
||||
|
||||
void ProgressBar::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
dc.MeasureText(dc.theme->uiFont, " 100% ", &w, &h);
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, " 100% ", &w, &h);
|
||||
}
|
||||
|
||||
void ProgressBar::Draw(UIContext &dc) {
|
||||
|
||||
+11
-6
@@ -273,10 +273,10 @@ struct Margins {
|
||||
Margins(int8_t horiz, int8_t vert) : top(vert), bottom(vert), left(horiz), right(horiz) {}
|
||||
Margins(int8_t l, int8_t t, int8_t r, int8_t b) : top(t), bottom(b), left(l), right(r) {}
|
||||
|
||||
int horiz() {
|
||||
int horiz() const {
|
||||
return left + right;
|
||||
}
|
||||
int vert() {
|
||||
int vert() const {
|
||||
return top + bottom;
|
||||
}
|
||||
|
||||
@@ -292,10 +292,10 @@ struct Padding {
|
||||
Padding(float horiz, float vert) : top(vert), bottom(vert), left(horiz), right(horiz) {}
|
||||
Padding(float l, float t, float r, float b) : top(t), bottom(b), left(l), right(r) {}
|
||||
|
||||
float horiz() {
|
||||
float horiz() const {
|
||||
return left + right;
|
||||
}
|
||||
float vert() {
|
||||
float vert() const {
|
||||
return top + bottom;
|
||||
}
|
||||
|
||||
@@ -388,6 +388,7 @@ public:
|
||||
|
||||
// Override this for easy standard behaviour. No need to override Measure.
|
||||
virtual void GetContentDimensions(const UIContext &dc, float &w, float &h) const;
|
||||
virtual void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const;
|
||||
|
||||
// Called when the layout is done.
|
||||
void SetBounds(Bounds bounds) { bounds_ = bounds; }
|
||||
@@ -608,7 +609,7 @@ public:
|
||||
: ClickableItem(layoutParams), atlasImage_(image), iconImage_(-1), centered_(false), highlighted_(false), selected_(false) {}
|
||||
|
||||
virtual void HighlightChanged(bool highlighted);
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override;
|
||||
void Draw(UIContext &dc) override;
|
||||
virtual void SetCentered(bool c) {
|
||||
centered_ = c;
|
||||
@@ -620,6 +621,7 @@ public:
|
||||
protected:
|
||||
// hackery
|
||||
virtual bool IsSticky() const { return false; }
|
||||
virtual float CalculateTextScale(const UIContext &dc, float availWidth) const;
|
||||
|
||||
std::string text_;
|
||||
std::string smallText_;
|
||||
@@ -708,11 +710,14 @@ public:
|
||||
}
|
||||
|
||||
void Draw(UIContext &dc) override;
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
|
||||
EventReturn OnClicked(EventParams &e);
|
||||
//allow external agents to toggle the checkbox
|
||||
void Toggle();
|
||||
private:
|
||||
float CalculateTextScale(const UIContext &dc, float availWidth) const;
|
||||
|
||||
bool *toggle_;
|
||||
std::string text_;
|
||||
std::string smallText_;
|
||||
@@ -742,7 +747,7 @@ public:
|
||||
TextView(const std::string &text, int textAlign, bool small, LayoutParams *layoutParams = 0)
|
||||
: InertView(layoutParams), text_(text), textAlign_(textAlign), textColor_(0xFFFFFFFF), small_(small), shadow_(false), focusable_(false), clip_(true) {}
|
||||
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override;
|
||||
void Draw(UIContext &dc) override;
|
||||
|
||||
void SetText(const std::string &text) { text_ = text; }
|
||||
|
||||
+42
-35
@@ -405,12 +405,12 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
|
||||
int numVisible = 0;
|
||||
|
||||
for (size_t i = 0; i < views_.size(); i++) {
|
||||
if (views_[i]->GetVisibility() == V_GONE)
|
||||
for (View *view : views_) {
|
||||
if (view->GetVisibility() == V_GONE)
|
||||
continue;
|
||||
numVisible++;
|
||||
|
||||
const LinearLayoutParams *linLayoutParams = views_[i]->GetLayoutParams()->As<LinearLayoutParams>();
|
||||
const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As<LinearLayoutParams>();
|
||||
|
||||
Margins margins = defaultMargins_;
|
||||
|
||||
@@ -422,22 +422,23 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
|
||||
if (orientation_ == ORIENT_HORIZONTAL) {
|
||||
MeasureSpec v = vert;
|
||||
if (v.type == UNSPECIFIED && measuredHeight_ != 0.0)
|
||||
if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f)
|
||||
v = MeasureSpec(AT_MOST, measuredHeight_);
|
||||
views_[i]->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert());
|
||||
view->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), v - (float)margins.vert());
|
||||
} else if (orientation_ == ORIENT_VERTICAL) {
|
||||
MeasureSpec h = horiz;
|
||||
if (h.type == UNSPECIFIED && measuredWidth_ != 0) h = MeasureSpec(AT_MOST, measuredWidth_);
|
||||
views_[i]->Measure(dc, h - (float)margins.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_));
|
||||
if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f)
|
||||
h = MeasureSpec(AT_MOST, measuredWidth_);
|
||||
view->Measure(dc, h - (float)margins.horiz(), MeasureSpec(UNSPECIFIED, measuredHeight_));
|
||||
}
|
||||
|
||||
float amount;
|
||||
if (orientation_ == ORIENT_HORIZONTAL) {
|
||||
amount = views_[i]->GetMeasuredWidth() + margins.horiz();
|
||||
maxOther = std::max(maxOther, views_[i]->GetMeasuredHeight() + margins.vert());
|
||||
amount = view->GetMeasuredWidth() + margins.horiz();
|
||||
maxOther = std::max(maxOther, view->GetMeasuredHeight() + margins.vert());
|
||||
} else {
|
||||
amount = views_[i]->GetMeasuredHeight() + margins.vert();
|
||||
maxOther = std::max(maxOther, views_[i]->GetMeasuredWidth() + margins.horiz());
|
||||
amount = view->GetMeasuredHeight() + margins.vert();
|
||||
maxOther = std::max(maxOther, view->GetMeasuredWidth() + margins.horiz());
|
||||
}
|
||||
|
||||
sum += amount;
|
||||
@@ -457,7 +458,6 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
// and distribute among the weighted ones.
|
||||
if (orientation_ == ORIENT_HORIZONTAL) {
|
||||
MeasureBySpec(layoutParams_->width, weightZeroSum, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, maxOther, vert, &measuredHeight_);
|
||||
|
||||
// If we've got stretch, allow growing to fill the parent.
|
||||
float allowedWidth = measuredWidth_;
|
||||
@@ -469,33 +469,36 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
float usedWidth = 0.0f;
|
||||
|
||||
// Redistribute the stretchy ones! and remeasure the children!
|
||||
for (size_t i = 0; i < views_.size(); i++) {
|
||||
if (views_[i]->GetVisibility() == V_GONE)
|
||||
for (View *view : views_) {
|
||||
if (view->GetVisibility() == V_GONE)
|
||||
continue;
|
||||
const LinearLayoutParams *linLayoutParams = views_[i]->GetLayoutParams()->As<LinearLayoutParams>();
|
||||
const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As<LinearLayoutParams>();
|
||||
|
||||
if (linLayoutParams && linLayoutParams->weight > 0.0f) {
|
||||
Margins margins = defaultMargins_;
|
||||
if (linLayoutParams->HasMargins())
|
||||
margins = linLayoutParams->margins;
|
||||
MeasureSpec v = vert;
|
||||
if (v.type == UNSPECIFIED && measuredHeight_ != 0.0)
|
||||
if (v.type == UNSPECIFIED && measuredHeight_ != 0.0f)
|
||||
v = MeasureSpec(AT_MOST, measuredHeight_);
|
||||
MeasureSpec h(AT_MOST, unit * linLayoutParams->weight - margins.horiz());
|
||||
if (horiz.type == EXACTLY) {
|
||||
h.type = EXACTLY;
|
||||
}
|
||||
views_[i]->Measure(dc, h, v - (float)margins.vert());
|
||||
usedWidth += views_[i]->GetMeasuredWidth();
|
||||
view->Measure(dc, h, v - (float)margins.vert());
|
||||
usedWidth += view->GetMeasuredWidth();
|
||||
maxOther = std::max(maxOther, view->GetMeasuredHeight() + margins.vert());
|
||||
}
|
||||
}
|
||||
|
||||
if (horiz.type == AT_MOST && measuredWidth_ < horiz.size) {
|
||||
measuredWidth_ += usedWidth;
|
||||
}
|
||||
|
||||
// Measure here in case maxOther moved (can happen due to word wrap.)
|
||||
MeasureBySpec(layoutParams_->height, maxOther, vert, &measuredHeight_);
|
||||
} else {
|
||||
MeasureBySpec(layoutParams_->height, weightZeroSum, vert, &measuredHeight_);
|
||||
MeasureBySpec(layoutParams_->width, maxOther, horiz, &measuredWidth_);
|
||||
|
||||
// If we've got stretch, allow growing to fill the parent.
|
||||
float allowedHeight = measuredHeight_;
|
||||
@@ -507,30 +510,34 @@ void LinearLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
float usedHeight = 0.0f;
|
||||
|
||||
// Redistribute the stretchy ones! and remeasure the children!
|
||||
for (size_t i = 0; i < views_.size(); i++) {
|
||||
if (views_[i]->GetVisibility() == V_GONE)
|
||||
for (View *view : views_) {
|
||||
if (view->GetVisibility() == V_GONE)
|
||||
continue;
|
||||
const LinearLayoutParams *linLayoutParams = views_[i]->GetLayoutParams()->As<LinearLayoutParams>();
|
||||
const LinearLayoutParams *linLayoutParams = view->GetLayoutParams()->As<LinearLayoutParams>();
|
||||
|
||||
if (linLayoutParams && linLayoutParams->weight > 0.0f) {
|
||||
Margins margins = defaultMargins_;
|
||||
if (linLayoutParams->HasMargins())
|
||||
margins = linLayoutParams->margins;
|
||||
MeasureSpec h = horiz;
|
||||
if (h.type == UNSPECIFIED && measuredWidth_ != 0.0)
|
||||
if (h.type == UNSPECIFIED && measuredWidth_ != 0.0f)
|
||||
h = MeasureSpec(AT_MOST, measuredWidth_);
|
||||
MeasureSpec v(AT_MOST, unit * linLayoutParams->weight - margins.vert());
|
||||
if (vert.type == EXACTLY) {
|
||||
v.type = EXACTLY;
|
||||
}
|
||||
views_[i]->Measure(dc, h - (float)margins.horiz(), v);
|
||||
usedHeight += views_[i]->GetMeasuredHeight();
|
||||
view->Measure(dc, h - (float)margins.horiz(), v);
|
||||
usedHeight += view->GetMeasuredHeight();
|
||||
maxOther = std::max(maxOther, view->GetMeasuredWidth() + margins.horiz());
|
||||
}
|
||||
}
|
||||
|
||||
if (vert.type == AT_MOST && measuredHeight_ < vert.size) {
|
||||
measuredHeight_ += usedHeight;
|
||||
}
|
||||
|
||||
// Measure here in case maxOther moved (can happen due to word wrap.)
|
||||
MeasureBySpec(layoutParams_->width, maxOther, horiz, &measuredWidth_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,15 +634,15 @@ void ScrollView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec ver
|
||||
}
|
||||
|
||||
// The scroll view itself simply obeys its parent - but also tries to fit the child if possible.
|
||||
MeasureBySpec(layoutParams_->width, 0.0f, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, 0.0f, vert, &measuredHeight_);
|
||||
MeasureBySpec(layoutParams_->width, horiz.size, horiz, &measuredWidth_);
|
||||
MeasureBySpec(layoutParams_->height, vert.size, vert, &measuredHeight_);
|
||||
|
||||
if (views_.size()) {
|
||||
if (orientation_ == ORIENT_HORIZONTAL) {
|
||||
views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED), MeasureSpec(UNSPECIFIED));
|
||||
views_[0]->Measure(dc, MeasureSpec(UNSPECIFIED, measuredWidth_), MeasureSpec(AT_MOST, measuredHeight_ - margins.vert()));
|
||||
MeasureBySpec(layoutParams_->height, views_[0]->GetMeasuredHeight(), vert, &measuredHeight_);
|
||||
} else {
|
||||
views_[0]->Measure(dc, MeasureSpec(AT_MOST, measuredWidth_ - margins.horiz()), MeasureSpec(UNSPECIFIED));
|
||||
views_[0]->Measure(dc, MeasureSpec(AT_MOST, measuredWidth_ - margins.horiz()), MeasureSpec(UNSPECIFIED, measuredHeight_));
|
||||
MeasureBySpec(layoutParams_->width, views_[0]->GetMeasuredWidth(), horiz, &measuredWidth_);
|
||||
}
|
||||
if (orientation_ == ORIENT_VERTICAL && vert.type != EXACTLY) {
|
||||
@@ -966,8 +973,8 @@ void AnchorLayout::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec v
|
||||
Size width = WRAP_CONTENT;
|
||||
Size height = WRAP_CONTENT;
|
||||
|
||||
MeasureSpec specW(UNSPECIFIED, 0.0f);
|
||||
MeasureSpec specH(UNSPECIFIED, 0.0f);
|
||||
MeasureSpec specW(UNSPECIFIED, measuredWidth_);
|
||||
MeasureSpec specH(UNSPECIFIED, measuredHeight_);
|
||||
|
||||
if (!overflow_) {
|
||||
if (horiz.type != UNSPECIFIED) {
|
||||
@@ -1106,9 +1113,9 @@ TabHolder::TabHolder(Orientation orientation, float stripSize, LayoutParams *lay
|
||||
currentTab_(0) {
|
||||
SetSpacing(0.0f);
|
||||
if (orientation == ORIENT_HORIZONTAL) {
|
||||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
tabStrip_ = new ChoiceStrip(orientation, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
tabStrip_->SetTopTabs(true);
|
||||
tabScroll_ = new ScrollView(orientation, new LayoutParams(FILL_PARENT, FILL_PARENT));
|
||||
tabScroll_ = new ScrollView(orientation, new LayoutParams(FILL_PARENT, WRAP_CONTENT));
|
||||
tabScroll_->Add(tabStrip_);
|
||||
Add(tabScroll_);
|
||||
} else {
|
||||
@@ -1162,7 +1169,7 @@ ChoiceStrip::ChoiceStrip(Orientation orientation, LayoutParams *layoutParams)
|
||||
void ChoiceStrip::AddChoice(const std::string &title) {
|
||||
StickyChoice *c = new StickyChoice(title, "",
|
||||
orientation_ == ORIENT_HORIZONTAL ?
|
||||
0 :
|
||||
nullptr :
|
||||
new LinearLayoutParams(FILL_PARENT, ITEM_HEIGHT));
|
||||
c->OnClick.Handle(this, &ChoiceStrip::OnChoiceClick);
|
||||
Add(c);
|
||||
@@ -1173,7 +1180,7 @@ void ChoiceStrip::AddChoice(const std::string &title) {
|
||||
void ChoiceStrip::AddChoice(ImageID buttonImage) {
|
||||
StickyChoice *c = new StickyChoice(buttonImage,
|
||||
orientation_ == ORIENT_HORIZONTAL ?
|
||||
0 :
|
||||
nullptr :
|
||||
new LinearLayoutParams(FILL_PARENT, ITEM_HEIGHT));
|
||||
c->OnClick.Handle(this, &ChoiceStrip::OnChoiceClick);
|
||||
Add(c);
|
||||
|
||||
Reference in new issue
Block a user