Skip to content

Commit

Permalink
Merge pull request #19020 from hrydgard/clickable-notifications
Browse files Browse the repository at this point in the history
Clickable notifications
  • Loading branch information
hrydgard authored Apr 12, 2024
2 parents 13ce255 + 6575ba5 commit 71a6372
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 15 deletions.
45 changes: 38 additions & 7 deletions Common/System/OSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,29 @@ OnScreenDisplay g_OSD;
// Effectively forever.
constexpr double forever_s = 10000000000.0;

OnScreenDisplay::~OnScreenDisplay() {
std::lock_guard<std::mutex> guard(mutex_);

double now = time_now_d();
for (auto &iter : entries_) {
if (iter.clickCallback) {
// Wasn't clicked, but let it free any data.
iter.clickCallback(false, iter.clickUserData);
}
}
}

void OnScreenDisplay::Update() {
std::lock_guard<std::mutex> guard(mutex_);

double now = time_now_d();
for (auto iter = entries_.begin(); iter != entries_.end(); ) {
if (now >= iter->endTime) {
if (iter->clickCallback) {
// Wasn't clicked, but let it free any data.
iter->clickCallback(false, iter->clickUserData);
iter->clickCallback = nullptr;
}
iter = entries_.erase(iter);
} else {
iter++;
Expand All @@ -41,10 +58,13 @@ float OnScreenDisplay::SidebarAlpha() const {
return saturatef(1.0f - ((float)timeSinceNudge - 0.1f) * 4.0f);
}

void OnScreenDisplay::DismissEntry(size_t index, double now) {
void OnScreenDisplay::ClickEntry(size_t index, double now) {
std::lock_guard<std::mutex> guard(mutex_);
if (index < entries_.size() && entries_[index].type != OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR) {
entries_[index].endTime = std::min(now + FadeoutTime(), entries_[index].endTime);
if (entries_[index].clickCallback) {
entries_[index].clickCallback(true, entries_[index].clickUserData);
}
}
}

Expand Down Expand Up @@ -90,7 +110,7 @@ void OnScreenDisplay::Show(OSDType type, std::string_view text, std::string_view
}
}

Entry msg;
Entry msg{};
msg.text = text;
msg.text2 = text2;
msg.iconName = icon;
Expand All @@ -116,7 +136,7 @@ void OnScreenDisplay::ShowAchievementUnlocked(int achievementID) {

double duration_s = 5.0;

Entry msg;
Entry msg{};
msg.numericID = achievementID;
msg.type = OSDType::ACHIEVEMENT_UNLOCKED;
msg.startTime = now;
Expand Down Expand Up @@ -149,7 +169,7 @@ void OnScreenDisplay::ShowAchievementProgress(int achievementID, bool show) {
}

// OK, let's make a new side-entry.
Entry entry;
Entry entry{};
entry.numericID = achievementID;
entry.type = OSDType::ACHIEVEMENT_PROGRESS;
entry.startTime = now;
Expand All @@ -175,7 +195,7 @@ void OnScreenDisplay::ShowChallengeIndicator(int achievementID, bool show) {
}

// OK, let's make a new side-entry.
Entry entry;
Entry entry{};
entry.numericID = achievementID;
entry.type = OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR;
entry.startTime = now;
Expand Down Expand Up @@ -208,7 +228,7 @@ void OnScreenDisplay::ShowLeaderboardTracker(int leaderboardTrackerID, const cha
}

// OK, let's make a new side-entry.
Entry entry;
Entry entry{};
entry.numericID = leaderboardTrackerID;
entry.type = OSDType::LEADERBOARD_TRACKER;
entry.startTime = now;
Expand Down Expand Up @@ -247,7 +267,7 @@ void OnScreenDisplay::SetProgressBar(std::string_view id, std::string_view messa
}
}

Entry bar;
Entry bar{};
bar.id = id;
bar.type = OSDType::PROGRESS_BAR;
bar.text = message;
Expand Down Expand Up @@ -298,3 +318,14 @@ void OnScreenDisplay::ClearAchievementStuff() {
}
}
}

void OnScreenDisplay::SetClickCallback(const char *id, void (*callback)(bool, void *), void *userdata) {
_dbg_assert_(callback != nullptr);
for (auto &ent : entries_) {
// protect against dupes.
if (ent.id == id && !ent.clickCallback) {
ent.clickCallback = callback;
ent.clickUserData = userdata;
}
}
}
13 changes: 12 additions & 1 deletion Common/System/OSD.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ enum class OSDType {
// Data holder for on-screen messages.
class OnScreenDisplay {
public:
~OnScreenDisplay();

// If you specify 0.0f as duration, a duration will be chosen automatically depending on type.
void Show(OSDType type, std::string_view text, float duration_s = 0.0f, const char *id = nullptr) {
Show(type, text, "", duration_s, id);
Expand Down Expand Up @@ -72,13 +74,22 @@ class OnScreenDisplay {
// Fades out everything related to achievements. Should be used on game shutdown.
void ClearAchievementStuff();

// Can't add an infinite number of "Show" functions, so starting to offer post-modification.
void SetClickCallback(const char *id, void (*callback)(bool, void *), void *userdata);

struct Entry {
OSDType type;
std::string text;
std::string text2;
std::string iconName;
int numericID;
std::string id;

// We could use std::function, but prefer to do it the oldschool way.
void (*clickCallback)(bool, void *);
void *clickUserData;

int instanceID;
double startTime;
double endTime;

Expand All @@ -91,7 +102,7 @@ class OnScreenDisplay {
std::vector<Entry> Entries();

// TODO: Use something more stable than the index.
void DismissEntry(size_t index, double now);
void ClickEntry(size_t index, double now);

static float FadeinTime() { return 0.1f; }
static float FadeoutTime() { return 0.25f; }
Expand Down
2 changes: 1 addition & 1 deletion GPU/Common/TextureReplacer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ class SaveTextureTask : public Task {
bool success = WriteTextureToPNG(&png, saveFilename, 0, rgbaData.data(), pitch, nullptr);
png_image_free(&png);
if (png.warning_or_error >= 2) {
ERROR_LOG(G3D, "Saving screenshot to PNG produced errors.");
ERROR_LOG(G3D, "Saving texture to PNG produced errors.");
} else if (success) {
NOTICE_LOG(G3D, "Saving texture for replacement: %08x / %dx%d in '%s'", replacedInfoHash, w, h, saveFilename.ToVisualString().c_str());
} else {
Expand Down
8 changes: 7 additions & 1 deletion UI/DevScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -870,8 +870,14 @@ void SystemInfoScreen::CreateInternalsTab(UI::ViewGroup *internals) {
g_OSD.Show(OSDType::MESSAGE_INFO, "Info");
return UI::EVENT_DONE;
});
// This one is clickable
internals->Add(new Choice(si->T("Success")))->OnClick.Add([&](UI::EventParams &) {
g_OSD.Show(OSDType::MESSAGE_SUCCESS, "Success");
g_OSD.Show(OSDType::MESSAGE_SUCCESS, "Success", 0.0f, "clickable");
g_OSD.SetClickCallback("clickable", [](bool clicked, void *) {
if (clicked) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.google.com/");
}
}, nullptr);
return UI::EVENT_DONE;
});
internals->Add(new Choice(sy->T("RetroAchievements")))->OnClick.Add([&](UI::EventParams &) {
Expand Down
12 changes: 11 additions & 1 deletion UI/NativeApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,17 @@ static void TakeScreenshot() {

bool success = TakeGameScreenshot(filename, g_Config.bScreenshotsAsPNG ? ScreenshotFormat::PNG : ScreenshotFormat::JPG, SCREENSHOT_OUTPUT);
if (success) {
g_OSD.Show(OSDType::MESSAGE_FILE_LINK, filename.ToString());
g_OSD.Show(OSDType::MESSAGE_FILE_LINK, filename.ToString(), 0.0f, "screenshot_link");
if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) {
g_OSD.SetClickCallback("screenshot_link", [](bool clicked, void *data) -> void {
Path *path = reinterpret_cast<Path *>(data);
if (clicked) {
System_ShowFileInFolder(*path);
} else {
delete path;
}
}, new Path(filename));
}
} else {
auto err = GetI18NCategory(I18NCat::ERRORS);
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Could not save screenshot file"));
Expand Down
8 changes: 4 additions & 4 deletions UI/OnScreenDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
edges[(size_t)pos].maxWidth = std::max(edges[(size_t)pos].maxWidth, measuredEntry.w);
}

std::vector<ClickZone> dismissZones;
std::vector<ClickZone> clickZones;

// Now, perform layout for all 8 edges.
for (size_t i = 0; i < (size_t)ScreenEdgePosition::VALUE_COUNT; i++) {
Expand Down Expand Up @@ -471,7 +471,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
case OSDType::MESSAGE_FILE_LINK:
case OSDType::ACHIEVEMENT_UNLOCKED:
// Save the location of the popup, for easy dismissal.
dismissZones.push_back(ClickZone{ (int)j, b });
clickZones.push_back(ClickZone{ (int)j, b });
break;
default:
break;
Expand All @@ -486,7 +486,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
}

std::lock_guard<std::mutex> lock(clickMutex_);
clickZones_ = dismissZones;
clickZones_ = clickZones;
}

std::string OnScreenMessagesView::DescribeText() const {
Expand All @@ -508,7 +508,7 @@ bool OnScreenMessagesView::Dismiss(float x, float y) {
double now = time_now_d();
for (auto &zone : clickZones_) {
if (zone.bounds.Contains(x, y)) {
g_OSD.DismissEntry(zone.index, now);
g_OSD.ClickEntry(zone.index, now);
dismissed = true;
}
}
Expand Down

0 comments on commit 71a6372

Please sign in to comment.