Merge pull request #17823 from hrydgard/more-achievement-ui-work

More achievement UI work
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2023-08-01 10:34:08 +02:00
commit f4b345bf7a
15 files changed
+316 -255

No files matched your search

+21 -54
View File
@@ -21,22 +21,6 @@ void OnScreenDisplay::Update() {
iter++;
}
}
for (auto iter = sideEntries_.begin(); iter != sideEntries_.end(); ) {
if (now >= iter->endTime) {
iter = sideEntries_.erase(iter);
} else {
iter++;
}
}
for (auto iter = bars_.begin(); iter != bars_.end(); ) {
if (now >= iter->endTime) {
iter = bars_.erase(iter);
} else {
iter++;
}
}
}
std::vector<OnScreenDisplay::Entry> OnScreenDisplay::Entries() {
@@ -44,16 +28,6 @@ std::vector<OnScreenDisplay::Entry> OnScreenDisplay::Entries() {
return entries_; // makes a copy.
}
std::vector<OnScreenDisplay::Entry> OnScreenDisplay::SideEntries() {
std::lock_guard<std::mutex> guard(mutex_);
return sideEntries_; // makes a copy.
}
std::vector<OnScreenDisplay::ProgressBar> OnScreenDisplay::ProgressBars() {
std::lock_guard<std::mutex> guard(mutex_);
return bars_; // makes a copy.
}
void OnScreenDisplay::NudgeSidebar() {
sideBarShowTime_ = time_now_d();
}
@@ -89,7 +63,7 @@ void OnScreenDisplay::Show(OSDType type, const std::string &text, const std::str
std::lock_guard<std::mutex> guard(mutex_);
if (id) {
for (auto iter = entries_.begin(); iter != entries_.end(); ++iter) {
if (iter->id && !strcmp(iter->id, id)) {
if (iter->id == id) {
Entry msg = *iter;
msg.endTime = now + duration_s;
msg.text = text;
@@ -111,7 +85,9 @@ void OnScreenDisplay::Show(OSDType type, const std::string &text, const std::str
msg.startTime = now;
msg.endTime = now + duration_s;
msg.type = type;
msg.id = id;
if (id) {
msg.id = id;
}
entries_.insert(entries_.begin(), msg);
}
@@ -132,7 +108,7 @@ void OnScreenDisplay::ShowAchievementProgress(int achievementID, bool show) {
double now = time_now_d();
// There can only be one of these at a time.
for (auto &entry : sideEntries_) {
for (auto &entry : entries_) {
if (entry.type == OSDType::ACHIEVEMENT_PROGRESS) {
if (!show) {
// Hide and eventually delete it.
@@ -158,13 +134,13 @@ void OnScreenDisplay::ShowAchievementProgress(int achievementID, bool show) {
entry.type = OSDType::ACHIEVEMENT_PROGRESS;
entry.startTime = now;
entry.endTime = now + forever_s;
sideEntries_.insert(sideEntries_.begin(), entry);
entries_.insert(entries_.begin(), entry);
}
void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) {
double now = time_now_d();
for (auto &entry : sideEntries_) {
for (auto &entry : entries_) {
if (entry.numericID == achievementID && entry.type == OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR && !show) {
// Hide and eventually delete it.
entry.endTime = now + (double)FadeoutTime();
@@ -184,17 +160,19 @@ void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) {
entry.type = OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR;
entry.startTime = now;
entry.endTime = now + forever_s;
sideEntries_.insert(sideEntries_.begin(), entry);
entries_.insert(entries_.begin(), entry);
}
void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const char *trackerText, bool show) { // show=true is used both for create and update.
double now = time_now_d();
for (auto &entry : sideEntries_) {
for (auto &entry : entries_) {
if (entry.numericID == leaderboardTrackerID && entry.type == OSDType::LEADERBOARD_TRACKER) {
if (show) {
// Just an update.
entry.text = trackerText ? trackerText : "";
// Bump the end-time, in case it was fading out.
entry.endTime = now + forever_s;
} else {
// Keep the current text, hide and eventually delete it.
entry.endTime = now + (double)FadeoutTime();
@@ -218,7 +196,7 @@ void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const cha
if (trackerText) {
entry.text = trackerText;
}
sideEntries_.insert(sideEntries_.begin(), entry);
entries_.insert(entries_.begin(), entry);
}
void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float duration_s) {
@@ -235,32 +213,33 @@ void OnScreenDisplay::SetProgressBar(std::string id, std::string &&message, floa
bool found = false;
std::lock_guard<std::mutex> guard(mutex_);
for (auto &bar : bars_) {
if (bar.id == id) {
for (auto &bar : entries_) {
if (bar.type == OSDType::PROGRESS_BAR && bar.id == id) {
bar.minValue = minValue;
bar.maxValue = maxValue;
bar.progress = progress;
bar.message = message;
bar.text = message;
bar.endTime = now + 60.0; // Nudge the progress bar to keep it shown.
return;
}
}
ProgressBar bar;
Entry bar;
bar.id = id;
bar.message = std::move(message);
bar.type = OSDType::PROGRESS_BAR;
bar.text = std::move(message);
bar.minValue = minValue;
bar.maxValue = maxValue;
bar.progress = progress;
bar.startTime = now + delay;
bar.endTime = now + 60.0; // Show the progress bar for 60 seconds, then fade it out.
bars_.push_back(bar);
entries_.push_back(bar);
}
void OnScreenDisplay::RemoveProgressBar(std::string id, bool success, float delay_s) {
std::lock_guard<std::mutex> guard(mutex_);
for (auto iter = bars_.begin(); iter != bars_.end(); iter++) {
if (iter->id == id) {
for (auto iter = entries_.begin(); iter != entries_.end(); iter++) {
if (iter->type == OSDType::PROGRESS_BAR && iter->id == id) {
if (success) {
// Quickly shoot up to max, if we weren't there.
if (iter->maxValue != 0.0f) {
@@ -293,16 +272,4 @@ void OnScreenDisplay::ClearAchievementStuff() {
break;
}
}
for (auto &iter : sideEntries_) {
switch (iter.type) {
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
case OSDType::ACHIEVEMENT_UNLOCKED:
case OSDType::ACHIEVEMENT_PROGRESS:
case OSDType::LEADERBOARD_TRACKER:
iter.endTime = now;
break;
default:
break;
}
}
}
+7 -11
View File
@@ -21,6 +21,10 @@ enum class OSDType {
ACHIEVEMENT_CHALLENGE_INDICATOR, // Achievement icon ONLY, no auto-hide
LEADERBOARD_TRACKER,
PROGRESS_BAR,
VALUE_COUNT,
};
// Data holder for on-screen messages.
@@ -67,31 +71,23 @@ public:
std::string text2;
std::string iconName;
int numericID;
const char *id;
std::string id;
double startTime;
double endTime;
};
struct ProgressBar {
std::string id;
std::string message;
// Progress-bar-only data:
float minValue;
float maxValue;
float progress;
double startTime;
double endTime;
};
std::vector<Entry> Entries();
std::vector<Entry> SideEntries();
std::vector<ProgressBar> ProgressBars();
static float FadeinTime() { return 0.1f; }
static float FadeoutTime() { return 0.25f; }
private:
std::vector<Entry> entries_;
std::vector<Entry> sideEntries_;
std::vector<ProgressBar> bars_;
std::mutex mutex_;
double sideBarShowTime_ = 0.0;
+6 -7
View File
@@ -25,18 +25,18 @@ static constexpr Size ITEM_HEIGHT = 64.f;
static constexpr float MIN_TEXT_SCALE = 0.8f;
static constexpr float MAX_ITEM_SIZE = 65535.0f;
void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured) {
void MeasureBySpec(Size sz, float contentDim, MeasureSpec spec, float *measured) {
if (sz == WRAP_CONTENT) {
if (spec.type == UNSPECIFIED)
*measured = contentWidth;
*measured = contentDim;
else if (spec.type == AT_MOST)
*measured = contentWidth < spec.size ? contentWidth : spec.size;
*measured = contentDim < spec.size ? contentDim : spec.size;
else if (spec.type == EXACTLY)
*measured = spec.size;
} 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 = std::max(spec.size, contentWidth);
*measured = std::max(spec.size, contentDim);
else
*measured = spec.size;
} else if (spec.type == EXACTLY || (spec.type == AT_MOST && *measured > spec.size)) {
@@ -46,7 +46,7 @@ void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measure
}
}
void ApplyBoundBySpec(float &bound, MeasureSpec spec) {
static void ApplyBoundBySpec(float &bound, MeasureSpec spec) {
switch (spec.type) {
case AT_MOST:
bound = bound < spec.size ? bound : spec.size;
@@ -122,9 +122,8 @@ void View::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) {
MeasureBySpec(layoutParams_->height, contentH, vert, &measuredHeight_);
}
// Default values
void View::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
// Default values
w = 10.0f;
h = 10.0f;
}
+47 -45
View File
@@ -824,55 +824,57 @@ void AnchorLayout::MeasureViews(const UIContext &dc, MeasureSpec horiz, MeasureS
}
}
static void ApplyAnchorLayoutParams(float measuredWidth, float measuredHeight, const Bounds &container, const AnchorLayoutParams *params, Bounds *vBounds) {
vBounds->w = measuredWidth;
vBounds->h = measuredHeight;
// Clamp width/height to our own
if (vBounds->w > container.w) vBounds->w = container.w;
if (vBounds->h > container.h) vBounds->h = container.h;
float left = 0, top = 0, right = 0, bottom = 0;
bool center = false;
if (params) {
left = params->left;
top = params->top;
right = params->right;
bottom = params->bottom;
center = params->center;
}
if (left > NONE) {
vBounds->x = container.x + left;
if (center)
vBounds->x -= vBounds->w * 0.5f;
} else if (right > NONE) {
vBounds->x = container.x2() - right - vBounds->w;
if (center) {
vBounds->x += vBounds->w * 0.5f;
}
} else {
// Both left and right are NONE. Center.
vBounds->x = (container.w - vBounds->w) / 2.0f + container.x;
}
if (top > NONE) {
vBounds->y = container.y + top;
if (center)
vBounds->y -= vBounds->h * 0.5f;
} else if (bottom > NONE) {
vBounds->y = container.y2() - bottom - vBounds->h;
if (center)
vBounds->y += vBounds->h * 0.5f;
} else {
// Both top and bottom are NONE. Center.
vBounds->y = (container.h - vBounds->h) / 2.0f + container.y;
}
}
void AnchorLayout::Layout() {
for (size_t i = 0; i < views_.size(); i++) {
const AnchorLayoutParams *params = views_[i]->GetLayoutParams()->As<AnchorLayoutParams>();
Bounds vBounds;
vBounds.w = views_[i]->GetMeasuredWidth();
vBounds.h = views_[i]->GetMeasuredHeight();
// Clamp width/height to our own
if (vBounds.w > bounds_.w) vBounds.w = bounds_.w;
if (vBounds.h > bounds_.h) vBounds.h = bounds_.h;
float left = 0, top = 0, right = 0, bottom = 0;
bool center = false;
if (params) {
left = params->left;
top = params->top;
right = params->right;
bottom = params->bottom;
center = params->center;
}
if (left > NONE) {
vBounds.x = bounds_.x + left;
if (center)
vBounds.x -= vBounds.w * 0.5f;
} else if (right > NONE) {
vBounds.x = bounds_.x2() - right - vBounds.w;
if (center) {
vBounds.x += vBounds.w * 0.5f;
}
} else {
// Both left and right are NONE. Center.
vBounds.x = (bounds_.w - vBounds.w) / 2.0f + bounds_.x;
}
if (top > NONE) {
vBounds.y = bounds_.y + top;
if (center)
vBounds.y -= vBounds.h * 0.5f;
} else if (bottom > NONE) {
vBounds.y = bounds_.y2() - bottom - vBounds.h;
if (center)
vBounds.y += vBounds.h * 0.5f;
} else {
// Both top and bottom are NONE. Center.
vBounds.y = (bounds_.h - vBounds.h) / 2.0f + bounds_.y;
}
ApplyAnchorLayoutParams(views_[i]->GetMeasuredWidth(), views_[i]->GetMeasuredHeight(), bounds_, params, &vBounds);
views_[i]->SetBounds(vBounds);
views_[i]->Layout();
}
+5 -2
View File
@@ -47,6 +47,7 @@
#include "Common/Thread/ThreadUtil.h"
#include "Common/GPU/Vulkan/VulkanLoader.h"
#include "Common/VR/PPSSPPVR.h"
#include "Common/System/OSD.h"
#include "Core/Config.h"
#include "Core/ConfigSettings.h"
#include "Core/ConfigValues.h"
@@ -282,6 +283,8 @@ static const ConfigSetting achievementSettings[] = {
ConfigSetting("AchievementsSoundEffects", &g_Config.bAchievementsSoundEffects, true, CfgFlag::DEFAULT),
ConfigSetting("AchievementsUnlockAudioFile", &g_Config.sAchievementsUnlockAudioFile, "", CfgFlag::DEFAULT),
ConfigSetting("AchievementsLeaderboardSubmitAudioFile", &g_Config.sAchievementsLeaderboardSubmitAudioFile, "", CfgFlag::DEFAULT),
ConfigSetting("AchievementsLeaderboardTrackerPos", &g_Config.iAchievementsLeaderboardTrackerPos, (int)ScreenEdgePosition::TOP_LEFT, CfgFlag::DEFAULT),
};
static const ConfigSetting cpuSettings[] = {
@@ -789,8 +792,8 @@ static const ConfigSetting networkSettings[] = {
ConfigSetting("UPnPUseOriginalPort", &g_Config.bUPnPUseOriginalPort, false, CfgFlag::PER_GAME),
ConfigSetting("EnableNetworkChat", &g_Config.bEnableNetworkChat, false, CfgFlag::PER_GAME),
ConfigSetting("ChatButtonPosition",&g_Config.iChatButtonPosition,BOTTOM_LEFT, CfgFlag::PER_GAME),
ConfigSetting("ChatScreenPosition",&g_Config.iChatScreenPosition,BOTTOM_LEFT, CfgFlag::PER_GAME),
ConfigSetting("ChatButtonPosition", &g_Config.iChatButtonPosition, (int)ScreenEdgePosition::BOTTOM_LEFT, CfgFlag::PER_GAME),
ConfigSetting("ChatScreenPosition", &g_Config.iChatScreenPosition, (int)ScreenEdgePosition::BOTTOM_LEFT, CfgFlag::PER_GAME),
ConfigSetting("EnableQuickChat", &g_Config.bEnableQuickChat, true, CfgFlag::PER_GAME),
ConfigSetting("QuickChat1", &g_Config.sQuickChat0, "Quick Chat 1", CfgFlag::PER_GAME),
ConfigSetting("QuickChat2", &g_Config.sQuickChat1, "Quick Chat 2", CfgFlag::PER_GAME),
+3 -11
View File
@@ -29,17 +29,6 @@
extern const char *PPSSPP_GIT_VERSION;
enum ChatPositions {
BOTTOM_LEFT = 0,
BOTTOM_CENTER = 1,
BOTOM_RIGHT = 2,
TOP_LEFT = 3,
TOP_CENTER = 4,
TOP_RIGHT = 5,
CENTER_LEFT = 6,
CENTER_RIGHT = 7,
};
namespace http {
class Request;
class RequestManager;
@@ -497,6 +486,9 @@ public:
bool bAchievementsSoundEffects;
bool bAchievementsLogBadMemReads;
// Positioning of the various notifications
int iAchievementsLeaderboardTrackerPos;
// Customizations
std::string sAchievementsUnlockAudioFile;
std::string sAchievementsLeaderboardSubmitAudioFile;
+12
View File
@@ -163,3 +163,15 @@ enum TiltTypes {
TILT_ACTION_BUTTON,
TILT_TRIGGER_BUTTONS,
};
enum class ScreenEdgePosition {
BOTTOM_LEFT = 0,
BOTTOM_CENTER = 1,
BOTTOM_RIGHT = 2,
TOP_LEFT = 3,
TOP_CENTER = 4,
TOP_RIGHT = 5,
CENTER_LEFT = 6,
CENTER_RIGHT = 7,
VALUE_COUNT,
};
+1 -1
View File
@@ -106,7 +106,7 @@ int DrawEngineCommon::ComputeNumVertsToDecode() const {
void DrawEngineCommon::DecodeVerts(u8 *dest) {
int decodeCounter = decodeCounter_;
for (; decodeCounter < numDrawCalls_; decodeCounter++) {
DecodeVertsStep(dest, decodeCounter, decodedVerts_, &drawCalls_[decodeCounter].uvScale); // NOTE! DecodeVertsStep can modify decodeCounter_!
DecodeVertsStep(dest, decodeCounter, decodedVerts_, &drawCalls_[decodeCounter].uvScale); // NOTE! DecodeVertsStep can modify the decodeCounter parameter!
}
decodeCounter_ = decodeCounter;
+12
View File
@@ -459,6 +459,11 @@ const char *GetCompilerABI() {
#endif
}
void SystemInfoScreen::update() {
TabbedUIDialogScreenWithGameBackground::update();
g_OSD.NudgeSidebar();
}
void SystemInfoScreen::CreateTabs() {
using namespace Draw;
using namespace UI;
@@ -852,6 +857,13 @@ void SystemInfoScreen::CreateTabs() {
g_OSD.ShowLeaderboardTracker(1, nullptr, false);
return UI::EVENT_DONE;
});
static const char *positions[] = { "Bottom Left", "Bottom Center", "Bottom Right", "Top Left", "Top Center", "Top Right", "Center Left", "Center Right", "None" };
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
internals->Add(new ItemHeader(ac->T("Notifications")));
internals->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardTrackerPos, ac->T("Leaderboard tracker"), positions, 0, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable);
#if PPSSPP_PLATFORM(ANDROID)
internals->Add(new Choice(si->T("Exception")))->OnClick.Add([&](UI::EventParams &) {
System_Notify(SystemNotification::TEST_JAVA_EXCEPTION);
+2
View File
@@ -113,6 +113,8 @@ public:
void CreateTabs() override;
void update() override;
protected:
bool ShowSearchControls() const override { return false; }
};
+9 -9
View File
@@ -894,15 +894,15 @@ protected:
// TODO: Shouldn't actually need bounds for this, Anchor can center too.
static UI::AnchorLayoutParams *AnchorInCorner(const Bounds &bounds, int corner, float xOffset, float yOffset) {
using namespace UI;
switch (g_Config.iChatButtonPosition) {
case 0: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, NONE, NONE, yOffset, true);
case 1: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), NONE, NONE, yOffset, true);
case 2: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, NONE, xOffset, yOffset, true);
case 3: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, yOffset, NONE, NONE, true);
case 4: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), yOffset, NONE, NONE, true);
case 5: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, yOffset, xOffset, NONE, true);
case 6: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, bounds.centerY(), NONE, NONE, true);
case 7: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, bounds.centerY(), xOffset, NONE, true);
switch ((ScreenEdgePosition)g_Config.iChatButtonPosition) {
case ScreenEdgePosition::BOTTOM_LEFT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, NONE, NONE, yOffset, true);
case ScreenEdgePosition::BOTTOM_CENTER: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), NONE, NONE, yOffset, true);
case ScreenEdgePosition::BOTTOM_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, NONE, xOffset, yOffset, true);
case ScreenEdgePosition::TOP_LEFT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, yOffset, NONE, NONE, true);
case ScreenEdgePosition::TOP_CENTER: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, bounds.centerX(), yOffset, NONE, NONE, true);
case ScreenEdgePosition::TOP_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, yOffset, xOffset, NONE, true);
case ScreenEdgePosition::CENTER_LEFT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, bounds.centerY(), NONE, NONE, true);
case ScreenEdgePosition::CENTER_RIGHT: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, NONE, bounds.centerY(), xOffset, NONE, true);
default: return new AnchorLayoutParams(WRAP_CONTENT, WRAP_CONTENT, xOffset, NONE, NONE, yOffset, true);
}
}
+183 -113
View File
@@ -156,12 +156,12 @@ static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, B
}
}
static void MeasureOSDProgressBar(const UIContext &dc, const OnScreenDisplay::ProgressBar &bar, float *width, float *height) {
static void MeasureOSDProgressBar(const UIContext &dc, const OnScreenDisplay::Entry &bar, float *width, float *height) {
*height = 36;
*width = 450.0f;
}
static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::ProgressBar &entry, Bounds bounds, int align, float alpha) {
static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::Entry &entry, Bounds bounds, int align, float alpha) {
uint32_t foreGround = whiteAlpha(alpha);
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
@@ -197,7 +197,7 @@ static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::ProgressB
dc.SetFontStyle(dc.theme->uiFont);
dc.SetFontScale(1.0f, 1.0f);
dc.DrawTextShadowRect(entry.message.c_str(), bounds, colorAlpha(0xFFFFFFFF, alpha), (align & FLAG_DYNAMIC_ASCII) | ALIGN_CENTER);
dc.DrawTextShadowRect(entry.text.c_str(), bounds, colorAlpha(0xFFFFFFFF, alpha), (align & FLAG_DYNAMIC_ASCII) | ALIGN_CENTER);
}
static void MeasureLeaderboardTracker(UIContext &dc, const std::string &text, float *width, float *height) {
@@ -226,143 +226,213 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
double now = time_now_d();
float y = 10.0f;
const float padding = 5.0f;
const float fadeinCoef = 1.0f / OnScreenDisplay::FadeinTime();
const float fadeoutCoef = 1.0f / OnScreenDisplay::FadeoutTime();
float sidebarAlpha = g_OSD.SidebarAlpha();
if (sidebarAlpha > 0.0f) {
// Draw side entries. Top entries should apply on top of them if there's a collision, so drawing
// these first makes sense.
const std::vector<OnScreenDisplay::Entry> sideEntries = g_OSD.SideEntries();
for (auto &entry : sideEntries) {
float tw, th;
struct LayoutEdge {
float height;
float maxWidth;
float alpha;
};
const rc_client_achievement_t *achievement = nullptr;
AchievementRenderStyle style;
struct MeasuredEntry {
float w;
float h;
float h1;
float alpha;
int align;
int align2;
AchievementRenderStyle style;
};
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
{
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
style = AchievementRenderStyle::PROGRESS_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
style = AchievementRenderStyle::CHALLENGE_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::LEADERBOARD_TRACKER:
{
MeasureLeaderboardTracker(dc, entry.text, &tw, &th);
break;
}
default:
continue;
}
Bounds b(10.0f, y, tw, th);
// We don't multiply in sidebarAlpha here because it shouldn't drive the below animation.
float alpha = Clamp((float)(entry.endTime - now) * fadeoutCoef, 0.0f, 1.0f);
// OK, render the thing.
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
RenderAchievement(dc, achievement, style, b, alpha * sidebarAlpha, entry.startTime, now, false);
break;
}
case OSDType::LEADERBOARD_TRACKER:
RenderLeaderboardTracker(dc, b, entry.text, alpha * sidebarAlpha);
break;
default:
continue;
}
y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations.
}
}
y = 10.0f;
// Draw the progress bars.
const std::vector<OnScreenDisplay::ProgressBar> bars = g_OSD.ProgressBars();
for (auto &bar : bars) {
float tw, th;
MeasureOSDProgressBar(dc, bar, &tw, &th);
Bounds b(0.0f, y, tw, th);
b.x = (bounds_.w - b.w) * 0.5f;
float enterAlpha = saturatef((float)(now - bar.startTime) * 4.0f);
float leaveAlpha = saturatef((float)(bar.endTime - now) * 4.0f);
float alpha = std::min(enterAlpha, leaveAlpha);
RenderOSDProgressBar(dc, bar, b, 0, alpha);
y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations.
}
// Draw the rest of the top-center messages.
// Grab all the entries. Makes a copy so we can release the lock ASAP.
const std::vector<OnScreenDisplay::Entry> entries = g_OSD.Entries();
for (const auto &entry : entries) {
dc.SetFontScale(1.0f, 1.0f);
// Messages that are wider than the screen are left-aligned instead of centered.
int align = 0;
// If we have newlines, we may be looking at ASCII debug output. But let's verify.
if (entry.text.find('\n') != 0) {
if (!UTF8StringHasNonASCII(entry.text.c_str()))
align |= FLAG_DYNAMIC_ASCII;
std::vector<MeasuredEntry> measuredEntries;
measuredEntries.resize(entries.size());
// Indexed by the enum ScreenEdgePosition.
LayoutEdge edges[(size_t)ScreenEdgePosition::VALUE_COUNT]{};
for (size_t i = 0; i < (size_t)ScreenEdgePosition::VALUE_COUNT; i++) {
edges[i].alpha = sidebarAlpha;
}
edges[(size_t)ScreenEdgePosition::TOP_CENTER].alpha = 1.0f;
ScreenEdgePosition typeEdges[(size_t)OSDType::VALUE_COUNT]{};
// Default to top.
for (int i = 0; i < (size_t)OSDType::VALUE_COUNT; i++) {
typeEdges[i] = ScreenEdgePosition::TOP_CENTER;
}
// TODO: Add ability to override these with g_Config settings.
typeEdges[(size_t)OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR] = ScreenEdgePosition::TOP_LEFT;
typeEdges[(size_t)OSDType::ACHIEVEMENT_PROGRESS] = ScreenEdgePosition::TOP_LEFT;
typeEdges[(size_t)OSDType::LEADERBOARD_TRACKER] = (ScreenEdgePosition)g_Config.iAchievementsLeaderboardTrackerPos;
dc.SetFontScale(1.0f, 1.0f);
// First pass: Measure all the sides.
for (size_t i = 0; i < entries.size(); i++) {
const auto &entry = entries[i];
auto &measuredEntry = measuredEntries[i];
ScreenEdgePosition pos = typeEdges[(size_t)entry.type];
if (pos == ScreenEdgePosition::VALUE_COUNT) {
// NONE.
continue;
}
float tw, th = 0.0f, h1 = 0.0f;
measuredEntry.align = 0;
measuredEntry.align2 = 0;
// If we have newlines, we may be looking at ASCII debug output. But let's verify.
if (entry.text.find('\n') != std::string::npos) {
if (!UTF8StringHasNonASCII(entry.text.c_str()))
measuredEntry.align |= FLAG_DYNAMIC_ASCII;
}
if (entry.text2.find('\n') != std::string::npos) {
if (!UTF8StringHasNonASCII(entry.text2.c_str()))
measuredEntry.align2 |= FLAG_DYNAMIC_ASCII;
}
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
{
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
measuredEntry.style = AchievementRenderStyle::PROGRESS_INDICATOR;
MeasureAchievement(dc, achievement, measuredEntry.style, &measuredEntry.w, &measuredEntry.h);
break;
}
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
measuredEntry.style = AchievementRenderStyle::CHALLENGE_INDICATOR;
MeasureAchievement(dc, achievement, measuredEntry.style, &measuredEntry.w, &measuredEntry.h);
break;
}
case OSDType::LEADERBOARD_TRACKER:
{
MeasureLeaderboardTracker(dc, entry.text, &measuredEntry.w, &measuredEntry.h);
break;
}
case OSDType::ACHIEVEMENT_UNLOCKED:
{
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (achievement) {
MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, &tw, &th);
h1 = th;
}
tw = 550.0f;
if (!achievement)
continue;
measuredEntry.style = AchievementRenderStyle::UNLOCKED;
MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, &measuredEntry.w, &measuredEntry.h);
measuredEntry.h1 = measuredEntry.h;
measuredEntry.w = 550.0f;
break;
}
case OSDType::PROGRESS_BAR:
MeasureOSDProgressBar(dc, entry, &measuredEntry.w, &measuredEntry.h);
break;
default:
MeasureOSDEntry(dc, entry, align, &tw, &th, &h1);
MeasureOSDEntry(dc, entry, measuredEntry.align, &measuredEntry.w, &measuredEntry.h, &measuredEntry.h1);
break;
}
Bounds b(0.0f, y, tw, th);
float enterAlpha = saturatef((float)(now - entry.startTime) * fadeoutCoef);
float leaveAlpha = saturatef((float)(entry.endTime - now) * fadeoutCoef);
float alpha = std::min(enterAlpha, leaveAlpha);
measuredEntry.alpha = alpha;
if (tw > bounds_.w) {
// Left-aligned
b.x = 2;
} else {
// Centered
b.x = (bounds_.w - b.w) * 0.5f;
edges[(size_t)pos].height += (measuredEntry.h + 4.0f) * alpha;
edges[(size_t)pos].maxWidth = std::max(edges[(size_t)pos].maxWidth, measuredEntry.w);
}
// Now, perform layout for all 8 edges.
for (size_t i = 0; i < (size_t)ScreenEdgePosition::VALUE_COUNT; i++) {
if (edges[i].height == 0.0f) {
// Nothing on this side, ignore it entirely.
continue;
}
// Scale down if height doesn't fit.
float scale = 1.0f;
if (th > bounds_.h - y) {
// Scale down!
scale = std::max(0.15f, (bounds_.h - y) / th);
dc.SetFontScale(scale, scale);
b.w *= scale;
b.h *= scale;
// First, compute the start position.
float y = padding;
int horizAdj = 0;
int vertAdj = 0;
switch ((ScreenEdgePosition)i) {
case ScreenEdgePosition::TOP_LEFT: horizAdj = -1; vertAdj = -1; break;
case ScreenEdgePosition::CENTER_LEFT: horizAdj = -1; break;
case ScreenEdgePosition::BOTTOM_LEFT: horizAdj = -1; vertAdj = 1; break;
case ScreenEdgePosition::TOP_RIGHT: horizAdj = 1; vertAdj = -1; break;
case ScreenEdgePosition::CENTER_RIGHT: horizAdj = 1; break;
case ScreenEdgePosition::BOTTOM_RIGHT: horizAdj = 1; vertAdj = 1; break;
case ScreenEdgePosition::TOP_CENTER: vertAdj = -1; break;
case ScreenEdgePosition::BOTTOM_CENTER: vertAdj = 1; break;
default: break;
}
float alpha = Clamp((float)(entry.endTime - now) * 4.0f, 0.0f, 1.0f);
RenderOSDEntry(dc, entry, b, h1, align, alpha);
y += (b.h * scale + 4.0f) * alpha; // including alpha here gets us smooth animations.
if (vertAdj == 0) {
// Center vertically
y = (bounds_.h - edges[i].height) * 0.5f;
} else if (vertAdj == 1) {
y = (bounds_.h - edges[i].height);
}
// Then, loop through the entries and those belonging here, get rendered here.
for (size_t j = 0; j < (size_t)entries.size(); j++) {
auto &entry = entries[j];
if (typeEdges[(size_t)entry.type] != (ScreenEdgePosition)i) { // yes, i
continue;
}
auto &measuredEntry = measuredEntries[j];
float alpha = measuredEntry.alpha * edges[i].alpha;
Bounds b(padding, y, measuredEntry.w, measuredEntry.h);
if (horizAdj == 0) {
// Centered
b.x = (bounds_.w - b.w) * 0.5f;
} else if (horizAdj == 1) {
// Right-aligned
b.x = bounds_.w - (b.w + padding);
}
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
RenderAchievement(dc, achievement, measuredEntry.style, b, alpha, entry.startTime, now, false);
break;
}
case OSDType::LEADERBOARD_TRACKER:
RenderLeaderboardTracker(dc, b, entry.text, alpha);
break;
case OSDType::PROGRESS_BAR:
RenderOSDProgressBar(dc, entry, b, 0, alpha);
break;
default:
{
// Scale down if height doesn't fit.
float scale = 1.0f;
if (measuredEntry.h > bounds_.h - y) {
// Scale down!
scale = std::max(0.15f, (bounds_.h - y) / measuredEntry.h);
dc.SetFontScale(scale, scale);
b.w *= scale;
b.h *= scale;
}
float alpha = Clamp((float)(entry.endTime - now) * 4.0f, 0.0f, 1.0f);
RenderOSDEntry(dc, entry, b, measuredEntry.h1, measuredEntry.align, alpha);
break;
}
}
y += (measuredEntry.h + 4.0f) * measuredEntry.alpha;
}
}
}
+6 -1
View File
@@ -275,7 +275,7 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
using namespace UI;
if (!g_Config.bAchievementsEnable) {
viewGroup->Add(new TextView(ac->T("Achievements are disabled")));
viewGroup->Add(new NoticeView(NoticeLevel::INFO, ac->T("Achievements are disabled"), "", new LinearLayoutParams(Margins(5))));
} else if (Achievements::IsLoggedIn()) {
const rc_client_user_t *info = rc_client_get_user_info(Achievements::GetClient());
@@ -366,6 +366,11 @@ void RetroAchievementsSettingsScreen::CreateCustomizeTab(UI::ViewGroup *viewGrou
viewGroup->Add(new ItemHeader(ac->T("Sound effects")));
viewGroup->Add(new AudioFileChooser(&g_Config.sAchievementsUnlockAudioFile, ac->T("Achievement unlocked"), UISound::ACHIEVEMENT_UNLOCKED));
viewGroup->Add(new AudioFileChooser(&g_Config.sAchievementsLeaderboardSubmitAudioFile, ac->T("Leaderboard score submission"), UISound::LEADERBOARD_SUBMITTED));
static const char *positions[] = { "Bottom Left", "Bottom Center", "Bottom Right", "Top Left", "Top Center", "Top Right", "Center Left", "Center Right", "None" };
viewGroup->Add(new ItemHeader(ac->T("Notifications")));
viewGroup->Add(new PopupMultiChoice(&g_Config.iAchievementsLeaderboardTrackerPos, ac->T("Leaderboard tracker"), positions, 0, ARRAY_SIZE(positions), I18NCat::DIALOG, screenManager()))->SetEnabledPtr(&g_Config.bAchievementsEnable);
}
void RetroAchievementsSettingsScreen::CreateDeveloperToolsTab(UI::ViewGroup *viewGroup) {
+1
View File
@@ -42,6 +42,7 @@ In Encore mode - listings may be wrong below = In Encore mode - listings may be
Leaderboard score submission = Leaderboard score submission
Leaderboard submission is enabled = Leaderboard submission is enabled
Leaderboards = Leaderboards
Leaderboard tracker = Leaderboard tracker
Links = Links
Locked achievements = Locked achievements
Log bad memory accesses = Log bad memory accesses
+1 -1
View File
@@ -10,7 +10,7 @@ Can't log in to RetroAchievements right now = Can't log in to RetroAchievements
Challenge Mode = Utmanings-läge
Challenge Mode (no savestates) = Utmanings-läge (inga sparade state)
Contacting RetroAchievements server... = Contacting RetroAchievements server...
Customize = Inställningar
Customize = Anpassa
Earned = Du har tjänat %d av %d achievements, och %d of %d poäng
Encore Mode = Encore-läge (kan ta achievements igen)
How to use RetroAchievements = Hur man använder RetroAchievements