mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
221 lines
7.6 KiB
C++
221 lines
7.6 KiB
C++
#include "Common/UI/View.h"
|
|
#include "Common/UI/Context.h"
|
|
#include "Common/Render/DrawBuffer.h"
|
|
#include "Common/System/Request.h"
|
|
#include "Common/System/Display.h"
|
|
#include "Common/TimeUtil.h"
|
|
#include "Common/Data/Text/I18n.h"
|
|
#include "Common/Math/curves.h"
|
|
#include "Common/StringUtils.h"
|
|
#include "UI/MiscViews.h"
|
|
#include "UI/GameInfoCache.h"
|
|
#include "Core/Config.h"
|
|
|
|
TextWithImage::TextWithImage(ImageID imageID, std::string_view text, UI::LinearLayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams) {
|
|
using namespace UI;
|
|
SetSpacing(8.0f);
|
|
if (!layoutParams) {
|
|
layoutParams_->width = FILL_PARENT;
|
|
layoutParams_->height = ITEM_HEIGHT;
|
|
}
|
|
if (imageID.isValid()) {
|
|
Add(new ImageView(imageID, "", UI::IS_DEFAULT, new LinearLayoutParams(0.0f, UI::Gravity::G_VCENTER)));
|
|
}
|
|
Add(new TextView(text, new LinearLayoutParams(1.0f, UI::Gravity::G_VCENTER)));
|
|
}
|
|
|
|
CopyableText::CopyableText(ImageID imageID, std::string_view text, UI::LinearLayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams) {
|
|
using namespace UI;
|
|
SetSpacing(8.0f);
|
|
if (!layoutParams) {
|
|
layoutParams_->width = FILL_PARENT;
|
|
layoutParams_->height = ITEM_HEIGHT;
|
|
}
|
|
if (imageID.isValid()) {
|
|
Add(new ImageView(imageID, "", UI::IS_DEFAULT, new LinearLayoutParams(0.0f, UI::Gravity::G_VCENTER)));
|
|
}
|
|
Add(new TextView(text, new LinearLayoutParams(1.0f, UI::Gravity::G_VCENTER)))->SetBig(true);
|
|
|
|
std::string textStr(text); // We need to store the text in the lambda context.
|
|
Add(new Choice(ImageID("I_FILE_COPY"), new LinearLayoutParams()))->OnClick.Add([textStr](UI::EventParams &) {
|
|
System_CopyStringToClipboard(textStr);
|
|
});
|
|
}
|
|
|
|
TopBar::TopBar(const UIContext &ctx, TopBarFlags flags, std::string_view title, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams), flags_(flags) {
|
|
using namespace UI;
|
|
SetSpacing(10.0f);
|
|
if (!layoutParams) {
|
|
layoutParams_->width = UI::FILL_PARENT;
|
|
layoutParams_->height = 64.0f;
|
|
}
|
|
|
|
auto dlg = GetI18NCategory(I18NCat::DIALOG);
|
|
backButton_ = Add(new Choice(ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)));
|
|
backButton_->OnClick.Add([](UI::EventParams &e) {
|
|
e.bubbleResult = DR_BACK;
|
|
});
|
|
|
|
if (!title.empty()) {
|
|
TextView *titleView = Add(new TextView(title, ALIGN_VCENTER, false, new LinearLayoutParams(1.0f, Gravity::G_VCENTER)));
|
|
titleView->SetTextColor(ctx.GetTheme().itemDownStyle.fgColor);
|
|
titleView->SetBig(true);
|
|
// If using HCENTER, to balance the centering, add a spacer on the right.
|
|
// Add(new Spacer(50.0f));
|
|
}
|
|
|
|
if (flags & TopBarFlags::ContextMenuButton) {
|
|
Choice *menuButton = Add(new Choice(ImageID("I_THREE_DOTS"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)));
|
|
menuButton->OnClick.Add([this](UI::EventParams &e) {
|
|
this->OnContextMenuClick.Trigger(e);
|
|
});
|
|
}
|
|
}
|
|
|
|
SettingInfoMessage::SettingInfoMessage(int align, float cutOffY, UI::AnchorLayoutParams *lp)
|
|
: UI::LinearLayout(ORIENT_HORIZONTAL, lp), cutOffY_(cutOffY) {
|
|
using namespace UI;
|
|
SetSpacing(0.0f);
|
|
Add(new Spacer(10.0f));
|
|
text_ = Add(new TextView("", align, false, new LinearLayoutParams(1.0, Margins(0, 10))));
|
|
Add(new Spacer(10.0f));
|
|
}
|
|
|
|
void SettingInfoMessage::Show(std::string_view text, const UI::View *refView) {
|
|
if (refView) {
|
|
Bounds b = refView->GetBounds();
|
|
const UI::AnchorLayoutParams *lp = GetLayoutParams()->As<UI::AnchorLayoutParams>();
|
|
if (lp) {
|
|
if (cutOffY_ != -1.0f && b.y >= cutOffY_) {
|
|
ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, 80.0f, lp->right, lp->bottom, lp->centering));
|
|
} else {
|
|
ReplaceLayoutParams(new UI::AnchorLayoutParams(lp->width, lp->height, lp->left, g_display.dp_yres - 80.0f - 40.0f, lp->right, lp->bottom, lp->centering));
|
|
}
|
|
}
|
|
}
|
|
if (text_) {
|
|
text_->SetText(text);
|
|
}
|
|
timeShown_ = time_now_d();
|
|
}
|
|
|
|
void SettingInfoMessage::Draw(UIContext &dc) {
|
|
static const double FADE_TIME = 1.0;
|
|
static const float MAX_ALPHA = 0.9f;
|
|
|
|
// Let's show longer messages for more time (guesstimate at reading speed.)
|
|
// Note: this will give multibyte characters more time, but they often have shorter words anyway.
|
|
double timeToShow = std::max(1.5, text_->GetText().size() * 0.05);
|
|
|
|
double sinceShow = time_now_d() - timeShown_;
|
|
float alpha = MAX_ALPHA;
|
|
if (timeShown_ == 0.0 || sinceShow > timeToShow + FADE_TIME) {
|
|
alpha = 0.0f;
|
|
} else if (sinceShow > timeToShow) {
|
|
alpha = MAX_ALPHA - MAX_ALPHA * (float)((sinceShow - timeToShow) / FADE_TIME);
|
|
}
|
|
|
|
UI::Style style = dc.GetTheme().tooltipStyle;
|
|
|
|
if (alpha >= 0.001f) {
|
|
uint32_t bgColor = alphaMul(style.background.color, alpha);
|
|
dc.FillRect(UI::Drawable(bgColor), bounds_);
|
|
}
|
|
|
|
uint32_t textColor = alphaMul(style.fgColor, alpha);
|
|
text_->SetTextColor(textColor);
|
|
ViewGroup::Draw(dc);
|
|
showing_ = sinceShow <= timeToShow; // Don't consider fade time
|
|
}
|
|
|
|
std::string SettingInfoMessage::GetText() const {
|
|
return (showing_ && text_) ? text_->GetText() : "";
|
|
}
|
|
|
|
void ShinyIcon::Draw(UIContext &dc) {
|
|
UI::DrawIconShine(dc, bounds_, 1.0f, animated_);
|
|
UI::ImageView::Draw(dc);
|
|
}
|
|
|
|
class SimpleGameIconView : public UI::InertView {
|
|
public:
|
|
SimpleGameIconView(const Path &gamePath, UI::LayoutParams *layoutParams = 0)
|
|
: InertView(layoutParams), gamePath_(gamePath) {
|
|
}
|
|
|
|
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override {
|
|
h = UI::ITEM_HEIGHT;
|
|
float aspect = 1.0f;
|
|
if (textureHeight_ > 0) {
|
|
aspect = static_cast<float>(textureWidth_) / static_cast<float>(textureHeight_);
|
|
}
|
|
w = h * aspect;
|
|
}
|
|
|
|
void Draw(UIContext &dc) override {
|
|
std::shared_ptr<GameInfo> info = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath_, GameInfoFlags::ICON);
|
|
if (!info->Ready(GameInfoFlags::ICON) || !info->icon.texture) {
|
|
return;
|
|
}
|
|
|
|
Draw::Texture *texture = info->icon.texture;
|
|
|
|
textureWidth_ = texture->Width();
|
|
textureHeight_ = texture->Height();
|
|
|
|
dc.Flush();
|
|
dc.GetDrawContext()->BindTexture(0, texture);
|
|
dc.Draw()->Rect(bounds_.x, bounds_.y, bounds_.w, bounds_.h, 0xFFFFFFFF);
|
|
dc.Flush();
|
|
dc.RebindTexture();
|
|
|
|
// Draw the gear icon
|
|
const AtlasImage *gearImage = dc.Draw()->GetAtlas()->getImage(ImageID("I_GEAR_SMALL"));
|
|
dc.Draw()->DrawImage(ImageID("I_GEAR_SMALL"), bounds_.x + 1, bounds_.y2() - gearImage->h - 1, 1.0f);
|
|
}
|
|
|
|
std::string DescribeText() const override { return ""; }
|
|
|
|
private:
|
|
Path gamePath_;
|
|
int textureWidth_ = 0;
|
|
int textureHeight_ = 0;
|
|
};
|
|
|
|
PaneTitleBar::PaneTitleBar(const Path &gamePath, std::string_view title, const std::string_view settingsCategory, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams), gamePath_(gamePath) {
|
|
using namespace UI;
|
|
SetSpacing(10.0f);
|
|
if (!layoutParams) {
|
|
layoutParams_->width = UI::FILL_PARENT;
|
|
layoutParams_->height = ITEM_HEIGHT;
|
|
}
|
|
|
|
auto dlg = GetI18NCategory(I18NCat::DIALOG);
|
|
|
|
if (!title.empty()) {
|
|
SimpleTextView *titleView = Add(new SimpleTextView(title, new LinearLayoutParams(0.0f, Gravity::G_VCENTER, Margins(10, 0, 20, 0))));
|
|
titleView->SetBig(true);
|
|
// If using HCENTER, to balance the centering, add a spacer on the right.
|
|
}
|
|
|
|
Add(new Spacer(10.0f, new LinearLayoutParams(1.0f)));
|
|
|
|
// Now add the game icon.
|
|
if (!gamePath.empty() && g_Config.IsGameSpecific()) {
|
|
Add(new SimpleGameIconView(gamePath_, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)));
|
|
}
|
|
|
|
if (!settingsCategory.empty()) {
|
|
std::string settingsUrl;
|
|
if (settingsCategory[0] == '/') {
|
|
settingsUrl = join("https://www.ppsspp.org", settingsCategory);
|
|
} else {
|
|
settingsUrl = join("https://www.ppsspp.org/docs/settings/", settingsCategory);
|
|
}
|
|
Choice *helpButton = Add(new Choice(ImageID("I_INFO"), new LinearLayoutParams()));
|
|
helpButton->OnClick.Add([settingsUrl](UI::EventParams &) {
|
|
System_LaunchUrl(LaunchUrlType::BROWSER_URL, settingsUrl);
|
|
});
|
|
}
|
|
}
|