Add banners on the top of settings pages, if editing game-specific settings show the icon.

This commit is contained in:
Henrik Rydgård committed 2025-11-09 08:51:41 +01:00
1 parent b6850eb26e
commit 6d1973edfb
38 files changed
+294 -122

No files matched your search

+1
View File
@@ -484,6 +484,7 @@
<ClInclude Include="Render\Text\draw_text_uwp.h" />
<ClInclude Include="Render\Text\draw_text_win.h" />
<ClInclude Include="LogReporting.h" />
<ClInclude Include="Render\Text\Font.h" />
<ClInclude Include="RiscVEmitter.h" />
<ClInclude Include="Serialize\SerializeDeque.h" />
<ClInclude Include="Serialize\SerializeFuncs.h" />
+3
View File
@@ -701,6 +701,9 @@
<ClInclude Include="UI\TabHolder.h">
<Filter>UI</Filter>
</ClInclude>
<ClInclude Include="Render\Text\Font.h">
<Filter>Render\Text</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />
+4
View File
@@ -1,11 +1,15 @@
#pragma once
#include <cstdlib>
#include <string_view>
namespace hash {
// Fairly decent function for hashing strings.
uint32_t Adler32(const uint8_t *data, size_t len);
inline uint32_t Adler32(std::string_view data) {
return Adler32((const uint8_t *)data.data(), data.size());
}
} // namespace hash
+2 -2
View File
@@ -109,13 +109,13 @@ std::vector<Data> Bucket::Resolve(int image_width, Image *dest) {
std::sort(data.begin(), data.end(), CompareByArea);
for (int i = 0; i < (int)data.size(); i++) {
if ((i + 1) % 2000 == 0) {
printf("Resolving (%i / %i)\n", i, (int)data.size());
// printf("Resolving (%i / %i)\n", i, (int)data.size());
}
int idx = (int)data[i].w;
int idy = (int)data[i].h;
if (idx > 1 && idy > 1) {
assert(idx <= image_width);
for (int ty = 0; ty < 2047; ty++) {
for (int ty = 0; ty < 2047; ty++) { // TODO: Maybe remove this limit?
if (ty + idy + 1 > (int)dest->height()) {
// Every 16 lines of new space needed, grow the image.
masq.resize(image_width, ty + idy + 16);
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <string>
#include <string_view>
#include "Common/Common.h"
#include "Common/Render/TextureAtlas.h"
#include "Common/Data/Hash/Hash.h"
enum class FontStyleFlags {
Default = 0,
Bold = 1,
Italic = 16,
};
ENUM_CLASS_BITOPS(FontStyleFlags);
struct FontStyle {
FontStyle() {}
FontStyle(FontID atlasFnt, std::string_view name, int size, FontStyleFlags _flags = FontStyleFlags::Default) : atlasFont(atlasFnt), fontName(name), sizePts(size), flags(_flags) {}
u32 Hash() const {
u32 hash = fontName.empty() ? 0 : hash::Adler32(fontName);
hash ^= sizePts;
hash ^= (int)flags << 10;
return hash;
}
FontID atlasFont{nullptr};
// For native fonts:
std::string fontName;
int sizePts = 0;
FontStyleFlags flags = FontStyleFlags::Default;
};
+3 -1
View File
@@ -16,6 +16,7 @@
#include "Common/Data/Text/WrapText.h"
#include "Common/Render/DrawBuffer.h"
#include "Common/Render/Text/Font.h"
namespace Draw {
class DrawContext;
@@ -45,8 +46,9 @@ public:
virtual ~TextDrawer() = default;
virtual bool IsReady() const { return true; }
virtual uint32_t SetFont(const char *fontName, int size, int flags) = 0;
virtual uint32_t SetOrCreateFont(const FontStyle &style) = 0;
virtual void SetFont(uint32_t fontHandle) = 0; // Shortcut once you've set the font once.
void SetFontScale(float xscale, float yscale);
void MeasureString(std::string_view str, float *w, float *h);
void MeasureStringRect(std::string_view str, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT);
+8 -5
View File
@@ -44,12 +44,10 @@ bool TextDrawerAndroid::IsReady() const {
return cls_textRenderer != nullptr && method_measureText != nullptr && method_renderText != nullptr;
}
uint32_t TextDrawerAndroid::SetFont(const char *fontName, int size, int flags) {
uint32_t TextDrawerAndroid::SetOrCreateFont(const FontStyle &style) {
// We will only use the default font but just for consistency let's still involve
// the font name.
uint32_t fontHash = fontName ? hash::Adler32((const uint8_t *)fontName, strlen(fontName)) : 1337;
fontHash ^= size;
fontHash ^= flags << 10;
const uint32_t fontHash = style.Hash();
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
@@ -59,7 +57,11 @@ uint32_t TextDrawerAndroid::SetFont(const char *fontName, int size, int flags) {
// Just chose a factor that looks good, don't know what unit size is in anyway.
AndroidFontEntry entry{};
entry.size = ((float)size * 1.4f) / dpiScale_;
entry.size = ((float)style.sizePts * 1.4f) / dpiScale_;
if (style.flags & FontStyleFlags::Bold)
entry.bold = true;
if (style.flags & FontStyleFlags::Italic)
entry.italic = true;
fontMap_[fontHash] = entry;
fontHash_ = fontHash;
return fontHash;
@@ -126,6 +128,7 @@ bool TextDrawerAndroid::DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextS
imageHeight = 1;
// WARN_LOG(Log::G3D, "Text: '%.*s' (%02x)", (int)str.length(), str.data(), str[0]);
// TODO: Handle bold/italic
jintArray imageData = (jintArray)env->CallStaticObjectMethod(cls_textRenderer, method_renderText, jstr, size);
env->DeleteLocalRef(jstr);
+3 -1
View File
@@ -11,6 +11,8 @@
struct AndroidFontEntry {
float size;
bool bold;
bool italic;
};
class TextDrawerAndroid : public TextDrawer {
@@ -19,7 +21,7 @@ public:
~TextDrawerAndroid();
bool IsReady() const override;
uint32_t SetFont(const char *fontName, int size, int flags) override;
uint32_t SetOrCreateFont(const FontStyle &style) override;
void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once.
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
+1 -1
View File
@@ -16,7 +16,7 @@ public:
TextDrawerCocoa(Draw::DrawContext *draw);
~TextDrawerCocoa();
uint32_t SetFont(const char *fontName, int size, int flags) override;
uint32_t SetOrCreateFont(const FontStyle &style) override;
void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once.
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
+28 -14
View File
@@ -83,12 +83,26 @@ public:
// Create an attributed string with string and font information
CGFloat fontSize = ceilf((height / dpiScale) * 1.25f);
INFO_LOG(Log::G3D, "Creating cocoa typeface '%s' size %d (effective size %0.1f)", APPLE_FONT, height, fontSize);
CTFontRef font = CTFontCreateWithName(CFSTR(APPLE_FONT), fontSize, nil);
CTFontSymbolicTraits traits = 0;
if (bold) traits |= kCTFontTraitBold;
if (italic) traits |= kCTFontTraitItalic;
CTFontRef base = CTFontCreateWithName(CFSTR(APPLE_FONT), fontSize, nil);
CTFontRef font = CTFontCreateCopyWithSymbolicTraits(base, fontSize, NULL, traits, traits); // desired & mask
if (!font) {
// Skip the traits.
font = base;
} else {
CFRelease(base);
}
_dbg_assert_(font != nil);
// CTFontRef font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, fontSize, nil);
attributes = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id)font, kCTFontAttributeName,
kCFBooleanTrue, kCTForegroundColorFromContextAttributeName, // Lets us specify the color later.
nil];
attributes = @{
(__bridge id)kCTFontAttributeName: (__bridge id)font,
(__bridge id)kCTForegroundColorFromContextAttributeName: (__bridge id)kCFBooleanTrue,
};
CFRelease(font);
}
void Destroy() {
@@ -97,7 +111,8 @@ public:
NSDictionary* attributes = nil;
std::string fname;
int height;
int bold;
bool bold;
bool italic;
float dpiScale;
};
@@ -110,10 +125,8 @@ TextDrawerCocoa::~TextDrawerCocoa() {
}
// TODO: Share with other backends.
uint32_t TextDrawerCocoa::SetFont(const char *fontName, int size, int flags) {
uint32_t fontHash = fontName ? hash::Adler32((const uint8_t *)fontName, strlen(fontName)) : 0;
fontHash ^= size;
fontHash ^= flags << 10;
uint32_t TextDrawerCocoa::SetOrCreateFont(const FontStyle &style) {
const uint32_t fontHash = style.Hash();
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
@@ -122,14 +135,15 @@ uint32_t TextDrawerCocoa::SetFont(const char *fontName, int size, int flags) {
}
std::string fname;
if (fontName)
fname = fontName;
if (!style.fontName.empty())
fname = std::string(style.fontName);
else
fname = APPLE_FONT;
TextDrawerFontContext *font = new TextDrawerFontContext();
font->bold = false;
font->height = size;
font->bold = style.flags & FontStyleFlags::Bold;
font->italic = style.flags & FontStyleFlags::Italic;
font->height = style.sizePts;
font->fname = fname;
font->dpiScale = dpiScale_;
font->Create();
+5 -6
View File
@@ -23,10 +23,8 @@ TextDrawerQt::~TextDrawerQt() {
ClearFonts();
}
uint32_t TextDrawerQt::SetFont(const char *fontName, int size, int flags) {
uint32_t fontHash = fontName && strlen(fontName) ? hash::Adler32((const uint8_t *)fontName, strlen(fontName)) : 0;
fontHash ^= size;
fontHash ^= flags << 10;
uint32_t TextDrawerQt::SetOrCreateFont(const FontStyle &style) {
const uint32_t fontHash = style.Hash();
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
@@ -34,8 +32,9 @@ uint32_t TextDrawerQt::SetFont(const char *fontName, int size, int flags) {
return fontHash;
}
QFont *font = fontName ? new QFont(fontName) : new QFont();
font->setPixelSize((int)((size + 6) / dpiScale_));
QFont *font = !style.fontName.empty() ? new QFont(style.fontName.c_str()) : new QFont();
font->setPixelSize((int)((style.sizePts + 6) / dpiScale_));
fontMap_[fontHash] = font;
fontHash_ = fontHash;
return fontHash;
+1 -1
View File
@@ -14,7 +14,7 @@ public:
TextDrawerQt(Draw::DrawContext *draw);
~TextDrawerQt();
uint32_t SetFont(const char *fontName, int size, int flags) override;
uint32_t SetOrCreateFont(const FontStyle &style) override;
void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once.
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
+5 -7
View File
@@ -245,10 +245,8 @@ int TextDrawerSDL::FindFallbackFonts(uint32_t missingGlyph, int ptSize) {
return -1;
}
uint32_t TextDrawerSDL::SetFont(const char *fontName, int size, int flags) {
uint32_t fontHash = fontName && strlen(fontName) ? hash::Adler32((const uint8_t *)fontName, strlen(fontName)) : 0;
fontHash ^= size;
fontHash ^= flags << 10;
uint32_t TextDrawerSDL::SetOrCreateFont(const FontStyle &style) {
const uint32_t fontHash = style.Hash();
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
@@ -256,10 +254,10 @@ uint32_t TextDrawerSDL::SetFont(const char *fontName, int size, int flags) {
return fontHash;
}
const char *useFont = fontName ? fontName : "Roboto-Condensed.ttf";
const int ptSize = (int)((size + 6) / dpiScale_);
std::string useFont = !style.fontName.empty() ? style.fontName : std::string("Roboto-Condensed.ttf");
const int ptSize = (int)((style.sizePts + 6) / dpiScale_);
TTF_Font *font = TTF_OpenFont(useFont, ptSize);
TTF_Font *font = TTF_OpenFont(useFont.c_str(), ptSize);
if (!font) {
File::FileInfo fileInfo;
+1 -1
View File
@@ -19,7 +19,7 @@ public:
TextDrawerSDL(Draw::DrawContext *draw);
~TextDrawerSDL();
uint32_t SetFont(const char *fontName, int size, int flags) override;
uint32_t SetOrCreateFont(const FontStyle &style) override;
void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once.
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
+13 -8
View File
@@ -41,7 +41,7 @@ public:
fname.c_str(),
fontCollection,
weight,
DWRITE_FONT_STYLE_NORMAL,
italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
(float)MulDiv(height, (int)(96.0f * (1.0f / dpiScale)), 72),
L"",
@@ -64,6 +64,7 @@ public:
std::wstring fname;
int height;
DWRITE_FONT_WEIGHT weight;
bool italic = false;
float dpiScale;
};
@@ -166,10 +167,8 @@ TextDrawerUWP::~TextDrawerUWP() {
delete ctx_;
}
uint32_t TextDrawerUWP::SetFont(const char *fontName, int size, int flags) {
uint32_t fontHash = fontName ? hash::Adler32((const uint8_t *)fontName, strlen(fontName)) : 0;
fontHash ^= size;
fontHash ^= flags << 10;
uint32_t TextDrawerUWP::SetOrCreateFont(const FontStyle &style) {
const uint32_t fontHash = style.Hash();
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
@@ -178,14 +177,20 @@ uint32_t TextDrawerUWP::SetFont(const char *fontName, int size, int flags) {
}
std::wstring fname;
if (fontName)
fname = ConvertUTF8ToWString(fontName);
if (!style.fontName.empty())
fname = ConvertUTF8ToWString(style.fontName);
else
fname = L"Tahoma";
TextDrawerFontContext *font = new TextDrawerFontContext();
font->weight = DWRITE_FONT_WEIGHT_NORMAL;
font->height = size;
if (style.flags & FontStyleFlags::Bold) {
font->weight = DWRITE_FONT_WEIGHT_BOLD;
}
if (style.flags & FontStyleFlags::Italic) {
font->italic = true;
}
font->height = style.sizePts;
font->fname = fname;
font->dpiScale = dpiScale_;
font->factory = m_dwriteFactory;
+1 -1
View File
@@ -19,7 +19,7 @@ public:
TextDrawerUWP(Draw::DrawContext *draw);
~TextDrawerUWP();
uint32_t SetFont(const char *fontName, int size, int flags) override;
uint32_t SetOrCreateFont(const FontStyle &style) override;
void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once.
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
+13 -10
View File
@@ -32,7 +32,7 @@ public:
}
// We apparently specify all font sizes in pts (1pt = 1.33px), so divide by only 72 for pixels.
int nHeight = -MulDiv(height, (int)(96.0f * (1.0f / dpiScale)), 72);
hFont = CreateFont(nHeight, 0, 0, 0, bold, 0,
hFont = CreateFont(nHeight, 0, 0, 0, weight, italic,
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
VARIABLE_PITCH, fname.c_str());
@@ -45,7 +45,8 @@ public:
HFONT hFont;
std::wstring fname;
int height;
int bold;
int weight;
bool italic = false;
float dpiScale;
};
@@ -84,10 +85,8 @@ TextDrawerWin32::~TextDrawerWin32() {
delete ctx_;
}
uint32_t TextDrawerWin32::SetFont(const char *fontName, int size, int flags) {
uint32_t fontHash = fontName ? hash::Adler32((const uint8_t *)fontName, strlen(fontName)) : 0;
fontHash ^= size;
fontHash ^= flags << 10;
uint32_t TextDrawerWin32::SetOrCreateFont(const FontStyle &style) {
const uint32_t fontHash = style.Hash();
auto iter = fontMap_.find(fontHash);
if (iter != fontMap_.end()) {
@@ -96,14 +95,18 @@ uint32_t TextDrawerWin32::SetFont(const char *fontName, int size, int flags) {
}
std::wstring fname;
if (fontName)
fname = ConvertUTF8ToWString(fontName);
if (!style.fontName.empty())
fname = ConvertUTF8ToWString(style.fontName);
else
fname = L"Tahoma";
TextDrawerFontContext *font = new TextDrawerFontContext();
font->bold = FW_LIGHT;
font->height = size;
font->weight = FW_LIGHT;
if (style.flags & FontStyleFlags::Bold) {
font->weight = FW_BOLD;
}
font->italic = (style.flags & FontStyleFlags::Italic);
font->height = style.sizePts;
font->fname = fname;
font->dpiScale = dpiScale_;
font->Create();
+2 -2
View File
@@ -15,8 +15,8 @@ class TextDrawerWin32 : public TextDrawer {
public:
TextDrawerWin32(Draw::DrawContext *draw);
~TextDrawerWin32();
uint32_t SetFont(const char *fontName, int size, int flags) override;
uint32_t SetOrCreateFont(const FontStyle &style) override;
void SetFont(uint32_t fontHandle) override; // Shortcut once you've set the font once.
bool DrawStringBitmap(std::vector<uint8_t> &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, std::string_view str, int align, bool fullColor) override;
+1 -1
View File
@@ -50,7 +50,7 @@ enum class LaunchUrlType {
};
void System_Vibrate(int length_ms);
void System_LaunchUrl(LaunchUrlType urlType, const char *url);
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url);
// It's sometimes a little unclear what should be a request, and what should be a separate function.
// Going forward, "optional" things (PPSSPP will still function alright without it) will be requests,
+9 -9
View File
@@ -16,7 +16,7 @@
#include "Common/Render/AtlasGen.h"
UIContext::UIContext() {
fontStyle_ = new UI::FontStyle();
fontStyle_ = new FontStyle();
bounds_ = Bounds(0, 0, g_display.dp_xres, g_display.dp_yres);
}
@@ -198,39 +198,39 @@ void UIContext::SetFontScale(float scaleX, float scaleY) {
fontScaleY_ = scaleY;
}
void UIContext::SetFontStyle(const UI::FontStyle &fontStyle) {
void UIContext::SetFontStyle(const FontStyle &fontStyle) {
*fontStyle_ = fontStyle;
if (textDrawer_) {
textDrawer_->SetFontScale(fontScaleX_, fontScaleY_);
textDrawer_->SetFont(fontStyle.fontName.c_str(), fontStyle.sizePts, fontStyle.flags);
textDrawer_->SetOrCreateFont(fontStyle);
}
}
void UIContext::MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align) const {
void UIContext::MeasureText(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align) const {
_dbg_assert_(str.data() != nullptr);
if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) {
float sizeFactor = (float)style.sizePts / 24.0f;
Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor);
Draw()->MeasureText(style.atlasFont, str, x, y);
} else {
textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags);
textDrawer_->SetOrCreateFont(style);
textDrawer_->SetFontScale(scaleX, scaleY);
textDrawer_->MeasureString(str, x, y);
textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags);
textDrawer_->SetOrCreateFont(*fontStyle_);
}
}
void UIContext::MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align) const {
void UIContext::MeasureTextRect(const FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align) const {
_dbg_assert_(str.data() != nullptr);
if (!textDrawer_ || (align & FLAG_DYNAMIC_ASCII)) {
float sizeFactor = (float)style.sizePts / 24.0f;
Draw()->SetFontScale(scaleX * sizeFactor, scaleY * sizeFactor);
Draw()->MeasureTextRect(style.atlasFont, str, bounds, x, y, align);
} else {
textDrawer_->SetFont(style.fontName.c_str(), style.sizePts, style.flags);
textDrawer_->SetOrCreateFont(style);
textDrawer_->SetFontScale(scaleX, scaleY);
textDrawer_->MeasureStringRect(str, bounds, x, y, align);
textDrawer_->SetFont(fontStyle_->fontName.c_str(), fontStyle_->sizePts, fontStyle_->flags);
textDrawer_->SetOrCreateFont(*fontStyle_);
}
}
+6 -6
View File
@@ -25,12 +25,12 @@ namespace Draw {
class DrawBuffer;
class TextDrawer;
struct FontStyle;
namespace UI {
struct Drawable;
struct EventParams;
struct Theme;
struct FontStyle;
class Event;
class View;
}
@@ -91,11 +91,11 @@ public:
// High level drawing functions. They generally assume the default texture to be bounds.
void SetFontStyle(const UI::FontStyle &style);
const UI::FontStyle &GetFontStyle() { return *fontStyle_; }
void SetFontStyle(const FontStyle &style);
const FontStyle &GetFontStyle() { return *fontStyle_; }
void SetFontScale(float scaleX, float scaleY);
void MeasureText(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align = 0) const;
void MeasureTextRect(const UI::FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align = 0) const;
void MeasureText(const FontStyle &style, float scaleX, float scaleY, std::string_view str, float *x, float *y, int align = 0) const;
void MeasureTextRect(const FontStyle &style, float scaleX, float scaleY, std::string_view str, const Bounds &bounds, float *x, float *y, int align = 0) const;
void DrawText(std::string_view str, float x, float y, uint32_t color, int align = 0);
void DrawTextShadow(std::string_view str, float x, float y, uint32_t color, int align = 0);
void DrawTextRect(std::string_view str, const Bounds &bounds, uint32_t color, int align = 0);
@@ -139,7 +139,7 @@ private:
float fontScaleX_ = 1.0f;
float fontScaleY_ = 1.0f;
UI::FontStyle *fontStyle_ = nullptr;
FontStyle *fontStyle_ = nullptr;
TextDrawer *textDrawer_ = nullptr;
Draw::SamplerState *sampler_ = nullptr;
+11 -3
View File
@@ -1054,12 +1054,20 @@ void TextView::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz
} else if (big_) {
style = &dc.GetTheme().uiFontBig;
}
dc.MeasureTextRect(*style, 1.0f, 1.0f, text_, bounds, &w, &h, textAlign_);
w += pad_ * 2.0f;
h += pad_ * 2.0f;
float measuredW;
float measuredH;
dc.MeasureTextRect(*style, 1.0f, 1.0f, text_, bounds, &measuredW, &measuredH, textAlign_);
w = measuredW + pad_ * 2.0f;
h = measuredH + pad_ * 2.0f;
if (bullet_) {
w += bulletOffset;
}
if (horiz.type == AT_MOST && bounds.w > measuredW) {
w = bounds.w;
}
if (vert.type == AT_MOST && bounds.h > measuredH) {
h = bounds.h;
}
}
void TextView::Draw(UIContext &dc) {
+1 -11
View File
@@ -16,6 +16,7 @@
#include <vector>
#include "Common/Render/TextureAtlas.h"
#include "Common/Render/Text/Font.h"
#include "Common/Math/lin/matrix4x4.h"
#include "Common/Math/math_util.h"
#include "Common/Math/geom2d.h"
@@ -76,17 +77,6 @@ struct Style {
ImageID image; // where applicable.
};
struct FontStyle {
FontStyle() {}
FontStyle(FontID atlasFnt, const char *name, int size) : atlasFont(atlasFnt), fontName(name), sizePts(size) {}
FontID atlasFont{ nullptr };
// For native fonts:
std::string fontName;
int sizePts = 0;
int flags = 0;
};
// To use with an UI atlas.
struct Theme {
FontStyle uiFont;
+1 -1
View File
@@ -769,7 +769,7 @@ static bool HasTextDrawer() {
if (textDrawer) {
textDrawer->SetFontScale(1.0f, 1.0f);
textDrawer->SetForcedDPIScale(1.0f);
textDrawer->SetFont(g_Config.sFont.c_str(), 18, 0);
textDrawer->SetOrCreateFont(FontStyle(FontID::invalid(), g_Config.sFont, 18, FontStyleFlags::Default));
}
textDrawerInited = true;
return textDrawer != nullptr;
+2 -3
View File
@@ -446,9 +446,8 @@ void System_Vibrate(int length_ms) {
length_ms = 25;
}
void System_LaunchUrl(LaunchUrlType urlType, const char *url)
{
QDesktopServices::openUrl(QUrl(url));
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
QDesktopServices::openUrl(QUrl(std::string(url).c_str()));
}
AudioBackend *System_CreateAudioBackend() {
+11 -12
View File
@@ -61,6 +61,7 @@ SDLJoystick *joystick = NULL;
#include "Common/Data/Collections/ConstMap.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Thread/ThreadUtil.h"
#include "Common/StringUtils.h"
#include "Core/System.h"
#include "Core/Core.h"
#include "Core/Config.h"
@@ -513,7 +514,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
void System_AskForPermission(SystemPermission permission) {}
PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; }
void System_LaunchUrl(LaunchUrlType urlType, const char *url) {
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
switch (urlType) {
case LaunchUrlType::BROWSER_URL:
case LaunchUrlType::MARKET_URL:
@@ -521,20 +522,20 @@ void System_LaunchUrl(LaunchUrlType urlType, const char *url) {
#if PPSSPP_PLATFORM(SWITCH)
Uuid uuid = { 0 };
WebWifiConfig conf;
webWifiCreate(&conf, NULL, url, uuid, 0);
webWifiCreate(&conf, NULL, std::string(url).c_str(), uuid, 0);
webWifiShow(&conf, NULL);
#elif defined(MOBILE_DEVICE)
INFO_LOG(Log::System, "Would have gone to %s but LaunchBrowser is not implemented on this platform", url);
INFO_LOG(Log::System, "Would have gone to %.*s but LaunchBrowser is not implemented on this platform", STR_VIEW(url));
#elif defined(_WIN32)
std::wstring wurl = ConvertUTF8ToWString(url);
ShellExecute(NULL, L"open", wurl.c_str(), NULL, NULL, SW_SHOWNORMAL);
#elif defined(__APPLE__)
OSXOpenURL(url);
OSXOpenURL(std::string(url).c_str());
#else
std::string command = std::string("xdg-open ") + url;
std::string command = join("xdg-open ", url);
int err = system(command.c_str());
if (err) {
INFO_LOG(Log::System, "Would have gone to %s but xdg-utils seems not to be installed", url);
INFO_LOG(Log::System, "Would have gone to %.*s but xdg-utils seems not to be installed", STR_VIEW(url));
}
#endif
break;
@@ -542,18 +543,16 @@ void System_LaunchUrl(LaunchUrlType urlType, const char *url) {
case LaunchUrlType::EMAIL_ADDRESS:
{
#if defined(MOBILE_DEVICE)
INFO_LOG(Log::System, "Would have opened your email client for %s but LaunchEmail is not implemented on this platform", url);
INFO_LOG(Log::System, "Would have opened your email client for %.*s but LaunchEmail is not implemented on this platform", STR_VIEW(url));
#elif defined(_WIN32)
std::wstring mailto = std::wstring(L"mailto:") + ConvertUTF8ToWString(url);
ShellExecute(NULL, L"open", mailto.c_str(), NULL, NULL, SW_SHOWNORMAL);
#elif defined(__APPLE__)
std::string mailToURL = std::string("mailto:") + url;
OSXOpenURL(mailToURL.c_str());
OSXOpenURL(join("mailto:", url).c_str());
#else
std::string command = std::string("xdg-email ") + url;
int err = system(command.c_str());
int err = system(join("xdg-email ", url).c_str());
if (err) {
INFO_LOG(Log::System, "Would have gone to %s but xdg-utils seems not to be installed", url);
INFO_LOG(Log::System, "Would have gone to %.*s but xdg-utils seems not to be installed", STR_VIEW(url));
}
#endif
break;
+1
View File
@@ -52,6 +52,7 @@
#include "UI/MainScreen.h"
#include "UI/BackgroundAudio.h"
#include "UI/SavedataScreen.h"
#include "UI/MiscViews.h"
constexpr GameInfoFlags g_desiredFlags = GameInfoFlags::PARAM_SFO | GameInfoFlags::ICON | GameInfoFlags::PIC0 | GameInfoFlags::PIC1 | GameInfoFlags::UNCOMPRESSED_SIZE | GameInfoFlags::SIZE;
+13 -1
View File
@@ -62,6 +62,7 @@
#include "UI/DiscordIntegration.h"
#include "UI/Background.h"
#include "UI/BackgroundAudio.h"
#include "UI/MiscViews.h"
#include "Common/File/FileUtil.h"
#include "Common/File/AndroidContentURI.h"
@@ -222,27 +223,38 @@ void GameSettingsScreen::CreateTabs() {
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
AddTab("GameSettingsGraphics", ms->T("Graphics"), ImageID("I_DISPLAY"), [this](UI::LinearLayout *parent) {
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
parent->Add(new PaneTitleBar(gamePath_, ms->T("Graphics"), "graphics", new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
CreateGraphicsSettings(parent);
});
AddTab("GameSettingsControls", ms->T("Controls"), ImageID("I_CONTROLLER"), [this](UI::LinearLayout *parent) {
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
parent->Add(new PaneTitleBar(gamePath_, ms->T("Controls"), "controls"));
CreateControlsSettings(parent);
});
AddTab("GameSettingsAudio", ms->T("Audio"), ImageID("I_SPEAKER_MAX"), [this](UI::LinearLayout *parent) {
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
parent->Add(new PaneTitleBar(gamePath_, ms->T("Audio"), "audio"));
CreateAudioSettings(parent);
});
AddTab("GameSettingsNetworking", ms->T("Networking"), ImageID("I_WIFI"), [this](UI::LinearLayout *parent) {
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
parent->Add(new PaneTitleBar(gamePath_, ms->T("Networking"), "network"));
CreateNetworkingSettings(parent);
});
AddTab("GameSettingsTools", ms->T("Tools"), ImageID("I_TOOLS"), [this](UI::LinearLayout *parent) {
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
parent->Add(new PaneTitleBar(gamePath_, ms->T("Tools"), "tools"));
CreateToolsSettings(parent);
});
AddTab("GameSettingsSystem", ms->T("System"), ImageID("I_PSP"), [this](UI::LinearLayout *parent) {
parent->SetSpacing(0);
auto ms = GetI18NCategory(I18NCat::MAINSETTINGS);
parent->Add(new PaneTitleBar(gamePath_, ms->T("System"), "system"));
CreateSystemSettings(parent);
});
+82
View File
@@ -5,7 +5,11 @@
#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;
@@ -58,6 +62,7 @@ TopBar::TopBar(const UIContext &ctx, bool usePortraitLayout, std::string_view ti
if (!title.empty()) {
TextView *titleView = Add(new TextView(title, ALIGN_VCENTER | FLAG_WRAP_TEXT, false, new LinearLayoutParams(1.0f, 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));
}
@@ -128,3 +133,80 @@ 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;
bool showGear_ = false;
};
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;
Add(new Spacer(10.0f, new LinearLayoutParams()));
if (!layoutParams) {
layoutParams_->width = UI::FILL_PARENT;
layoutParams_->height = ITEM_HEIGHT;
}
auto dlg = GetI18NCategory(I18NCat::DIALOG);
if (!title.empty()) {
TextView *titleView = Add(new TextView(title, ALIGN_VCENTER | FLAG_WRAP_TEXT, false, new LinearLayoutParams(1.0f, G_VCENTER, Margins(10, 0, 0, 0))));
titleView->SetBig(true);
// If using HCENTER, to balance the centering, add a spacer on the right.
// Add(new Spacer(50.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 = 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);
});
}
}
+12
View File
@@ -49,3 +49,15 @@ public:
private:
bool animated_ = true;
};
// Title at the top of a scrolling pane of settings. May later include a back button, but currently doesn't.
// The gamePath_ is used to draw the icon of the game who's settings are currently being edited.
// settingsCategory is used to build the help URL.
class PaneTitleBar : public UI::LinearLayout {
public:
PaneTitleBar(const Path &gamePath, std::string_view title, const std::string_view settingsCategory, UI::LayoutParams *layoutParams = nullptr);
private:
UI::Choice *backButton_ = nullptr;
Path gamePath_;
};
+1 -1
View File
@@ -852,7 +852,7 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
uiContext->Init(g_draw, texColorPipeline, colorPipeline, &ui_draw2d);
if (uiContext->Text()) {
uiContext->Text()->SetFont("Tahoma", 20, 0);
uiContext->Text()->SetOrCreateFont(FontStyle(FontID::invalid(), "Tahoma", 20, FontStyleFlags::Default));
}
g_screenManager->setUIContext(uiContext);
+1
View File
@@ -19,6 +19,7 @@ enum class TabDialogFlags {
Default = 0,
HorizontalOnlyIcons = 1,
VerticalShowIcons = 2,
AddTitles = 4,
};
ENUM_CLASS_BITOPS(TabDialogFlags);
+6 -6
View File
@@ -199,13 +199,13 @@ void UpdateTheme() {
}
#if defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP) || defined(USING_QT_UI)
ui_theme.uiFont = UI::FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 22);
ui_theme.uiFontSmall = UI::FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 17);
ui_theme.uiFontBig = UI::FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 28);
ui_theme.uiFont = FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 22);
ui_theme.uiFontSmall = FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 17);
ui_theme.uiFontBig = FontStyle(FontID("UBUNTU24"), g_Config.sFont.c_str(), 28, FontStyleFlags::Bold);
#else
ui_theme.uiFont = UI::FontStyle(FontID("UBUNTU24"), "", 20);
ui_theme.uiFontSmall = UI::FontStyle(FontID("UBUNTU24"), "", 15);
ui_theme.uiFontBig = UI::FontStyle(FontID("UBUNTU24"), "", 26);
ui_theme.uiFont = FontStyle(FontID("UBUNTU24"), "", 20);
ui_theme.uiFontSmall = FontStyle(FontID("UBUNTU24"), "", 15);
ui_theme.uiFontBig = FontStyle(FontID("UBUNTU24"), "", 26, FontStyleFlags::Bold);
#endif
ui_theme.checkOn = ImageID("I_CHECKEDBOX");
+1 -1
View File
@@ -604,7 +604,7 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
}
}
void System_LaunchUrl(LaunchUrlType urlType, const char *url) {
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
auto uri = ref new Windows::Foundation::Uri(ToPlatformString(url));
create_task(Windows::System::Launcher::LaunchUriAsync(uri)).then([](bool b) {});
+2 -2
View File
@@ -2,11 +2,11 @@
#include "Common/Data/Encoding/Utf8.h"
inline Platform::String ^ToPlatformString(std::string str) {
inline Platform::String ^ToPlatformString(std::string_view str) {
return ref new Platform::String(ConvertUTF8ToWString(str).c_str());
}
inline std::string FromPlatformString(Platform::String ^str) {
std::wstring wstr(str->Data());
return ConvertWStringToUTF8(wstr);
}
}
+1 -1
View File
@@ -131,7 +131,7 @@ static double g_lastKeepAwake = 0.0;
// Should this be configurable? 2 hours currently.
static constexpr double ACTIVITY_IDLE_TIMEOUT = 2.0 * 3600.0;
void System_LaunchUrl(LaunchUrlType urlType, const char *url) {
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
std::string u(url);
std::thread t = std::thread([u]() {
ShellExecute(NULL, L"open", ConvertUTF8ToWString(u).c_str(), NULL, NULL, SW_SHOWNORMAL);
+1 -1
View File
@@ -359,7 +359,7 @@ void System_Vibrate(int length_ms) {
PushCommand("vibrate", temp);
}
void System_LaunchUrl(LaunchUrlType urlType, const char *url) {
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
switch (urlType) {
case LaunchUrlType::BROWSER_URL: PushCommand("launchBrowser", url); break;
case LaunchUrlType::MARKET_URL: PushCommand("launchMarket", url); break;
+3 -3
View File
@@ -583,9 +583,9 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string
void System_Toast(std::string_view text) {}
void System_AskForPermission(SystemPermission permission) {}
void System_LaunchUrl(LaunchUrlType urlType, const char *url)
{
NSURL *nsUrl = [NSURL URLWithString:[NSString stringWithCString:url encoding:NSStringEncodingConversionAllowLossy]];
void System_LaunchUrl(LaunchUrlType urlType, std::string_view url) {
std::string strUrl(url);
NSURL *nsUrl = [NSURL URLWithString:[NSString stringWithCString:strUrl.c_str() encoding:NSStringEncodingConversionAllowLossy]];
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] openURL:nsUrl options:@{} completionHandler:nil];
});