OSD: Add semantics, move the the OSD state to common (while keeping the renderer in the UI).

This commit is contained in:
Henrik Rydgård 2023-06-20 14:40:46 +02:00
parent d6552a7673
commit 7cc8c6cea4
30 changed files with 204 additions and 179 deletions

View File

@ -2,8 +2,76 @@
#include "Common/System/System.h"
#include "Common/Log.h"
#include "Common/File/Path.h"
#include "Common/TimeUtil.h"
RequestManager g_requestManager;
OnScreenDisplay g_OSD;
void OnScreenDisplay::Update() {
std::lock_guard<std::mutex> guard(mutex_);
double now = time_now_d();
for (auto iter = messages_.begin(); iter != messages_.end(); ) {
if (now >= iter->endTime) {
iter = messages_.erase(iter);
} else {
iter++;
}
}
}
std::vector<OnScreenDisplay::Message> OnScreenDisplay::Messages() {
std::lock_guard<std::mutex> guard(mutex_);
return messages_;
}
void OnScreenDisplay::Show(OSDType type, const std::string &text, float duration_s, const char *id) {
// Automatic duration based on type.
if (duration_s <= 0.0f) {
switch (type) {
case OSDType::MESSAGE_ERROR:
case OSDType::MESSAGE_WARNING:
duration_s = 3.0f;
break;
case OSDType::MESSAGE_FILE_LINK:
duration_s = 5.0f;
break;
case OSDType::MESSAGE_SUCCESS:
duration_s = 2.0f;
break;
default:
duration_s = 1.5f;
break;
}
}
double now = time_now_d();
std::lock_guard<std::mutex> guard(mutex_);
if (id) {
for (auto iter = messages_.begin(); iter != messages_.end(); ++iter) {
if (iter->id && !strcmp(iter->id, id)) {
Message msg = *iter;
msg.endTime = now + duration_s;
msg.text = text;
messages_.erase(iter);
messages_.insert(messages_.begin(), msg);
return;
}
}
}
Message msg;
msg.text = text;
msg.endTime = now + duration_s;
msg.id = id;
messages_.insert(messages_.begin(), msg);
}
void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float duration_s) {
// TODO: translate "on" and "off"? Or just get rid of this whole thing?
Show(OSDType::MESSAGE_INFO, message + ": " + (on ? "on" : "off"), duration_s);
}
const char *RequestTypeAsString(SystemRequestType type) {
switch (type) {

View File

@ -4,6 +4,7 @@
#include <vector>
#include <functional>
#include <cstdint>
#include <mutex>
// Platform integration
@ -212,7 +213,41 @@ void System_PostUIMessage(const std::string &message, const std::string &param);
// Shows a visible message to the user.
// The default implementation in NativeApp.cpp uses our "osm" system (on screen messaging).
void System_NotifyUserMessage(const std::string &message, float duration = 1.0f, uint32_t color = 0x00FFFFFF, const char *id = nullptr);
enum class OSDType {
MESSAGE_INFO,
MESSAGE_SUCCESS,
MESSAGE_WARNING,
MESSAGE_ERROR,
MESSAGE_ERROR_DUMP, // displays lots of text (after the first line), small size
MESSAGE_FILE_LINK,
// PROGRESS_BAR,
// PROGRESS_INDETERMINATE,
};
// Data holder. This one is currently global.
class OnScreenDisplay {
public:
// If you specify 0 duration, a duration will be chosen automatically depending on type.
void Show(OSDType type, const std::string &message, float duration_s = 0.0f, const char *id = nullptr);
void ShowOnOff(const std::string &message, bool on, float duration_s = 0.0f);
bool IsEmpty() const { return messages_.empty(); }
void Update();
struct Message {
std::string text;
const char *id;
double endTime;
double duration;
};
std::vector<Message> Messages();
private:
std::vector<Message> messages_;
std::mutex mutex_;
};
extern OnScreenDisplay g_OSD;
// For these functions, most platforms will use the implementation provided in UI/AudioCommon.cpp,
// no need to implement separately.

View File

@ -378,7 +378,7 @@ void CWCheatEngine::CreateCheatFile() {
}
if (!File::Exists(filename_)) {
auto err = GetI18NCategory(I18NCat::ERRORS);
System_NotifyUserMessage(err->T("Unable to create cheat file, disk may be full"));
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Unable to create cheat file, disk may be full"));
}
}
}

View File

@ -456,7 +456,7 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD
if (!pspFileSystem.GetFileInfo(dirPath).exists) {
if (!pspFileSystem.MkDir(dirPath)) {
auto err = GetI18NCategory(I18NCat::ERRORS);
System_NotifyUserMessage(err->T("Unable to write savedata, disk may be full"));
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Unable to write savedata, disk may be full"));
}
}
@ -485,7 +485,7 @@ int SavedataParam::Save(SceUtilitySavedataParam* param, const std::string &saveD
if (EncryptData(decryptMode, cryptedData, &cryptedSize, &aligned_len, cryptedHash, (hasKey ? param->key : 0)) != 0) {
auto err = GetI18NCategory(I18NCat::ERRORS);
System_NotifyUserMessage(err->T("Save encryption failed. This save won't work on real PSP"), 6.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, err->T("Save encryption failed. This save won't work on real PSP"), 6.0f);
ERROR_LOG(SCEUTILITY,"Save encryption failed. This save won't work on real PSP");
delete[] cryptedData;
cryptedData = 0;
@ -775,8 +775,8 @@ u32 SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, con
// Don't notify the user if we're not going to upgrade the save.
if (!g_Config.bEncryptSave) {
auto di = GetI18NCategory(I18NCat::DIALOG);
System_NotifyUserMessage(di->T("When you save, it will load on a PSP, but not an older PPSSPP"), 6.0f);
System_NotifyUserMessage(di->T("Old savedata detected"), 6.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, di->T("When you save, it will load on a PSP, but not an older PPSSPP"), 6.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, di->T("Old savedata detected"), 6.0f);
}
} else {
if (decryptMode == 5 && prevCryptMode == 3) {
@ -787,8 +787,8 @@ u32 SavedataParam::LoadCryptedSave(SceUtilitySavedataParam *param, u8 *data, con
if (g_Config.bSavedataUpgrade) {
decryptMode = prevCryptMode;
auto di = GetI18NCategory(I18NCat::DIALOG);
System_NotifyUserMessage(di->T("When you save, it will not work on outdated PSP Firmware anymore"), 6.0f);
System_NotifyUserMessage(di->T("Old savedata detected"), 6.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, di->T("When you save, it will not work on outdated PSP Firmware anymore"), 6.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, di->T("Old savedata detected"), 6.0f);
}
}
hasKey = decryptMode > 1;

View File

@ -73,7 +73,7 @@ u32 BlockDevice::CalculateCRC(volatile bool *cancel) {
void BlockDevice::NotifyReadError() {
auto err = GetI18NCategory(I18NCat::ERRORS);
if (!reportedError_) {
System_NotifyUserMessage(err->T("Game disc read error - ISO corrupt"), 6.0f);
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Game disc read error - ISO corrupt"), 6.0f);
reportedError_ = true;
}
}

View File

@ -192,7 +192,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File
if (w32err == ERROR_DISK_FULL || w32err == ERROR_NOT_ENOUGH_QUOTA) {
// This is returned when the disk is full.
auto err = GetI18NCategory(I18NCat::ERRORS);
System_NotifyUserMessage(err->T("Disk full while writing data"));
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Disk full while writing data"));
error = SCE_KERNEL_ERROR_ERRNO_NO_PERM;
} else if (!success) {
error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;
@ -290,7 +290,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File
} else if (errno == ENOSPC) {
// This is returned when the disk is full.
auto err = GetI18NCategory(I18NCat::ERRORS);
System_NotifyUserMessage(err->T("Disk full while writing data"));
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Disk full while writing data"));
error = SCE_KERNEL_ERROR_ERRNO_NO_PERM;
} else {
error = SCE_KERNEL_ERROR_ERRNO_FILE_NOT_FOUND;
@ -365,7 +365,7 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
if (diskFull) {
ERROR_LOG(FILESYS, "Disk full");
auto err = GetI18NCategory(I18NCat::ERRORS);
System_NotifyUserMessage(err->T("Disk full while writing data"));
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Disk full while writing data"));
// We only return an error when the disk is actually full.
// When writing this would cause the disk to be full, so it wasn't written, we return 0.
if (MemoryStick_FreeSpace() == 0) {

View File

@ -1385,7 +1385,7 @@ int friendFinder(){
g_adhocServerIP.in.sin_addr.s_addr = INADDR_NONE;
if (g_Config.bEnableWlan && !net::DNSResolve(g_Config.proAdhocServer, "", &resolved, err)) {
ERROR_LOG(SCENET, "DNS Error Resolving %s\n", g_Config.proAdhocServer.c_str());
System_NotifyUserMessage(n->T("DNS Error Resolving ") + g_Config.proAdhocServer, 2.0f, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, n->T("DNS Error Resolving ") + g_Config.proAdhocServer);
}
if (resolved) {
for (auto ptr = resolved; ptr != NULL; ptr = ptr->ai_next) {
@ -1447,7 +1447,7 @@ int friendFinder(){
shutdown((int)metasocket, SD_BOTH);
closesocket((int)metasocket);
metasocket = (int)INVALID_SOCKET;
System_NotifyUserMessage(std::string(n->T("Disconnected from AdhocServer")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(error) + ")", 2.0, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Disconnected from AdhocServer")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(error) + ")");
// Mark all friends as timedout since we won't be able to detects disconnected friends anymore without being connected to Adhoc Server
peerlock.lock();
timeoutFriendsRecursive(friends);
@ -2191,7 +2191,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
iResult = bind((int)metasocket, &g_localhostIP.addr, sizeof(g_localhostIP.addr));
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Bind to alternate localhost[%s] failed(%i).", ip2str(g_localhostIP.in.sin_addr).c_str(), iResult);
System_NotifyUserMessage(std::string(n->T("Failed to Bind Localhost IP")) + " " + ip2str(g_localhostIP.in.sin_addr).c_str(), 2.0, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to Bind Localhost IP")) + " " + ip2str(g_localhostIP.in.sin_addr).c_str());
}
}
@ -2246,7 +2246,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
}
if (!done) {
ERROR_LOG(SCENET, "Socket error (%i) when connecting to AdhocServer [%s/%s:%u]", errorcode, g_Config.proAdhocServer.c_str(), ip2str(g_adhocServerIP.in.sin_addr).c_str(), ntohs(g_adhocServerIP.in.sin_port));
System_NotifyUserMessage(std::string(n->T("Failed to connect to Adhoc Server")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(errorcode) + ")", 1.0f, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to connect to Adhoc Server")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(errorcode) + ")");
return iResult;
}
}
@ -2268,10 +2268,9 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
socklen_t addrLen = sizeof(LocalIP);
memset(&LocalIP, 0, addrLen);
getsockname((int)metasocket, &LocalIP, &addrLen);
System_NotifyUserMessage(n->T("Network Initialized"), 1.0);
g_OSD.Show(OSDType::MESSAGE_SUCCESS, n->T("Network Initialized"), 1.0);
return 0;
}
else{
} else {
return SOCKET_ERROR;
}
}

View File

@ -1858,7 +1858,7 @@ int create_listen_socket(uint16_t port)
else {
ERROR_LOG(SCENET, "AdhocServer: Bind returned %i (Socket error %d)", bindresult, errno);
auto n = GetI18NCategory(I18NCat::NETWORKING);
System_NotifyUserMessage(std::string(n->T("AdhocServer Failed to Bind Port")) + " " + std::to_string(port), 3.0, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("AdhocServer Failed to Bind Port")) + " " + std::to_string(port));
}
// Close Socket

View File

@ -576,9 +576,9 @@ void __DisplayFlip(int cyclesLate) {
#ifndef _DEBUG
auto err = GetI18NCategory(I18NCat::ERRORS);
if (g_Config.bSoftwareRendering) {
System_NotifyUserMessage(err->T("Running slow: Try turning off Software Rendering"), 6.0f, 0xFF30D0D0);
g_OSD.Show(OSDType::MESSAGE_INFO, err->T("Running slow: Try turning off Software Rendering"));
} else {
System_NotifyUserMessage(err->T("Running slow: try frameskip, sound is choppy when slow"), 6.0f, 0xFF30D0D0);
g_OSD.Show(OSDType::MESSAGE_INFO, err->T("Running slow: try frameskip, sound is choppy when slow"));
}
#endif
hasNotifiedSlow = true;

View File

@ -277,7 +277,7 @@ static void __GameModeNotify(u64 userdata, int cyclesLate) {
if (peer != NULL)
truncate_cpy(name, sizeof(name), (const char*)peer->nickname.data);
WARN_LOG(SCENET, "GameMode: Unknown Source Port from [%s][%s:%u -> %u] (Result=%i, Size=%i)", name, mac2str(&sendermac).c_str(), senderport, ADHOC_GAMEMODE_PORT, ret, bufsz);
System_NotifyUserMessage(std::string(n->T("GM: Data from Unknown Port")) + std::string(" [") + std::string(name) + std::string("]:") + std::to_string(senderport) + std::string(" -> ") + std::to_string(ADHOC_GAMEMODE_PORT) + std::string(" (") + std::to_string(portOffset) + std::string(")"), 2.0, 0x0080ff);
g_OSD.Show(OSDType::MESSAGE_WARNING, std::string(n->T("GM: Data from Unknown Port")) + std::string(" [") + std::string(name) + std::string("]:") + std::to_string(senderport) + std::string(" -> ") + std::to_string(ADHOC_GAMEMODE_PORT) + std::string(" (") + std::to_string(portOffset) + std::string(")"));
peerlock.unlock();
}
// Keeping track of the source port for further communication, in case it was re-mapped by router or ISP for some reason.
@ -1507,7 +1507,7 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 f
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port));
auto n = GetI18NCategory(I18NCat::NETWORKING);
System_NotifyUserMessage(std::string(n->T("Failed to Bind Port")) + " " + std::to_string(port + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")), 3.0, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to Bind Port")) + " " + std::to_string(port + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")));
return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_NOT_AVAIL, "port not available");
}
@ -3524,7 +3524,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac,
else {
ERROR_LOG(SCENET, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port));
auto n = GetI18NCategory(I18NCat::NETWORKING);
System_NotifyUserMessage(std::string(n->T("Failed to Bind Port")) + " " + std::to_string(sport + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")), 3.0, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to Bind Port")) + " " + std::to_string(sport + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")));
}
// Close Socket
@ -4117,7 +4117,7 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int
}
else {
auto n = GetI18NCategory(I18NCat::NETWORKING);
System_NotifyUserMessage(std::string(n->T("Failed to Bind Port")) + " " + std::to_string(sport + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")), 3.0, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("Failed to Bind Port")) + " " + std::to_string(sport + portOffset) + "\n" + std::string(n->T("Please change your Port Offset")));
}
if (iResult == SOCKET_ERROR) {
@ -7782,7 +7782,7 @@ int matchingInputThread(int matchingId) // TODO: The MatchingInput thread is usi
if (peer != NULL)
truncate_cpy(name, sizeof(name), (const char*)peer->nickname.data);
WARN_LOG(SCENET, "InputLoop[%d]: Unknown Source Port from [%s][%s:%u -> %u] (Recved=%i, Length=%i)", matchingId, name, mac2str(&sendermac).c_str(), senderport, context->port, recvresult, rxbuflen);
System_NotifyUserMessage(std::string(n->T("AM: Data from Unknown Port")) + std::string(" [") + std::string(name) + std::string("]:") + std::to_string(senderport) + std::string(" -> ") + std::to_string(context->port) + std::string(" (") + std::to_string(portOffset) + std::string(")"), 2.0, 0x0080ff);
g_OSD.Show(OSDType::MESSAGE_WARNING, std::string(n->T("AM: Data from Unknown Port")) + std::string(" [") + std::string(name) + std::string("]:") + std::to_string(senderport) + std::string(" -> ") + std::to_string(context->port) + std::string(" (") + std::to_string(portOffset) + std::string(")"));
}
// Keep tracks of re-mapped peer's ports for further communication.
// Note: This will only works if this player were able to receives data on normal port from other players (ie. this player's port wasn't remapped)

View File

@ -190,7 +190,7 @@ bool PortManager::Initialize(const unsigned int timeout) {
ERROR_LOG(SCENET, "PortManager - upnpDiscover failed (error: %i) or No UPnP device detected", error);
if (g_Config.bEnableUPnP) {
auto n = GetI18NCategory(I18NCat::NETWORKING);
System_NotifyUserMessage(n->T("Unable to find UPnP device"), 2.0f, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_ERROR, n->T("Unable to find UPnP device"));
}
m_InitState = UPNP_INITSTATE_NONE;
#endif // WITH_UPNP
@ -215,11 +215,12 @@ bool PortManager::Add(const char* protocol, unsigned short port, unsigned short
{
if (g_Config.bEnableUPnP) {
WARN_LOG(SCENET, "PortManager::Add - the init was not done !");
System_NotifyUserMessage(n->T("UPnP need to be reinitialized"), 2.0f, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized"));
}
Terminate();
return false;
}
snprintf(port_str, sizeof(port_str), "%d", port);
snprintf(intport_str, sizeof(intport_str), "%d", intport);
// Only add new port map if it's not previously created by PPSSPP for current IP
@ -244,7 +245,7 @@ bool PortManager::Add(const char* protocol, unsigned short port, unsigned short
ERROR_LOG(SCENET, "PortManager - AddPortMapping failed (error: %i)", r);
if (r == UPNPCOMMAND_HTTP_ERROR) {
if (g_Config.bEnableUPnP) {
System_NotifyUserMessage(n->T("UPnP need to be reinitialized"), 2.0f, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized"));
}
Terminate(); // Most of the time errors occurred because the router is no longer reachable (ie. changed networks) so we should invalidate the state to prevent further lags due to timeouts
return false;
@ -270,7 +271,7 @@ bool PortManager::Remove(const char* protocol, unsigned short port) {
{
if (g_Config.bEnableUPnP) {
WARN_LOG(SCENET, "PortManager::Remove - the init was not done !");
System_NotifyUserMessage(n->T("UPnP need to be reinitialized"), 2.0f, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized"));
}
Terminate();
return false;
@ -282,7 +283,7 @@ bool PortManager::Remove(const char* protocol, unsigned short port) {
ERROR_LOG(SCENET, "PortManager - DeletePortMapping failed (error: %i)", r);
if (r == UPNPCOMMAND_HTTP_ERROR) {
if (g_Config.bEnableUPnP) {
System_NotifyUserMessage(n->T("UPnP need to be reinitialized"), 2.0f, 0x0000ff);
g_OSD.Show(OSDType::MESSAGE_INFO, n->T("UPnP need to be reinitialized"));
}
Terminate(); // Most of the time errors occurred because the router is no longer reachable (ie. changed networks) so we should invalidate the state to prevent further lags due to timeouts
return false;

View File

@ -2714,7 +2714,7 @@ void FramebufferManagerCommon::ShowScreenResolution() {
messageStream << gr->T("Window Size") << ": ";
messageStream << PSP_CoreParameter().pixelWidth << "x" << PSP_CoreParameter().pixelHeight;
System_NotifyUserMessage(messageStream.str(), 2.0f, 0xFFFFFF, "resize");
g_OSD.Show(OSDType::MESSAGE_INFO, messageStream.str(), 0.0f, "resize");
INFO_LOG(SYSTEM, "%s", messageStream.str().c_str());
}

View File

@ -450,9 +450,9 @@ void PresentationCommon::ShowPostShaderError(const std::string &errorString) {
}
}
if (!firstLine.empty()) {
System_NotifyUserMessage("Post-shader error: " + firstLine + "...:\n" + errorString, 10.0f, 0xFF3090FF);
g_OSD.Show(OSDType::MESSAGE_ERROR_DUMP, "Post-shader error: " + firstLine + "...:\n" + errorString, 10.0f);
} else {
System_NotifyUserMessage("Post-shader error, see log for details", 10.0f, 0xFF3090FF);
g_OSD.Show(OSDType::MESSAGE_ERROR, "Post-shader error, see log for details", 10.0f);
}
}

View File

@ -310,7 +310,7 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, VFSBackend *dir, bool isOverri
if (filenameWarning) {
auto err = GetI18NCategory(I18NCat::ERRORS);
System_NotifyUserMessage(err->T("textures.ini filenames may not be cross-platform (banned characters)"), 6.0f);
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("textures.ini filenames may not be cross-platform (banned characters)"), 6.0f);
}
if (ini.HasSection("hashranges")) {

View File

@ -88,7 +88,8 @@ GPU_DX9::GPU_DX9(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
// Disable hardware tessellation bacause DX9 is still unsupported.
ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
System_NotifyUserMessage(gr->T("Turn off Hardware Tessellation - unsupported"), 2.5f, 0xFF3030FF);
// TODO: Badly formulated
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("Turn off Hardware Tessellation - unsupported"));
}
}

View File

@ -606,7 +606,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat
ERROR_LOG(G3D, "Shader compilation failed, falling back to software transform");
}
if (!g_Config.bHideSlowWarnings) {
System_NotifyUserMessage(gr->T("hardware transform error - falling back to software"), 2.5f, 0xFF3030FF);
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("hardware transform error - falling back to software"), 2.5f);
}
delete vs;

View File

@ -122,7 +122,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
if (!drawEngine_.SupportsHWTessellation()) {
ERROR_LOG(G3D, "Hardware Tessellation is unsupported, falling back to software tessellation");
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
System_NotifyUserMessage(gr->T("Turn off Hardware Tessellation - unsupported"), 2.5f, 0xFF3030FF);
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("Turn off Hardware Tessellation - unsupported"));
}
}
}

View File

@ -803,7 +803,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
ERROR_LOG(G3D, "Vertex shader generation failed, falling back to software transform");
if (!g_Config.bHideSlowWarnings) {
System_NotifyUserMessage(gr->T("hardware transform error - falling back to software"), 2.5f, 0xFF3030FF);
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("hardware transform error - falling back to software"), 2.5f);
}
delete vs;

View File

@ -150,9 +150,9 @@ void TextureCacheGLES::StartFrame() {
auto err = GetI18NCategory(I18NCat::ERRORS);
if (standardScaleFactor_ > 1) {
System_NotifyUserMessage(err->T("Warning: Video memory FULL, reducing upscaling and switching to slow caching mode"), 2.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, err->T("Warning: Video memory FULL, reducing upscaling and switching to slow caching mode"), 2.0f);
} else {
System_NotifyUserMessage(err->T("Warning: Video memory FULL, switching to slow caching mode"), 2.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, err->T("Warning: Video memory FULL, switching to slow caching mode"), 2.0f);
}
}
}

View File

@ -513,9 +513,9 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) {
auto err = GetI18NCategory(I18NCat::ERRORS);
if (plan.scaleFactor > 1) {
System_NotifyUserMessage(err->T("Warning: Video memory FULL, reducing upscaling and switching to slow caching mode"), 2.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, err->T("Warning: Video memory FULL, reducing upscaling and switching to slow caching mode"), 2.0f);
} else {
System_NotifyUserMessage(err->T("Warning: Video memory FULL, switching to slow caching mode"), 2.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, err->T("Warning: Video memory FULL, switching to slow caching mode"), 2.0f);
}
// Turn off texture replacement for this texture.

View File

@ -122,7 +122,7 @@ static void __EmuScreenVblank()
if (g_Config.bDumpFrames && !startDumping)
{
avi.Start(PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
osm.Show(sy->T("AVI Dump started."), 0.5f);
g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump started."), 1.0f);
startDumping = true;
}
if (g_Config.bDumpFrames && startDumping)
@ -132,7 +132,7 @@ static void __EmuScreenVblank()
else if (!g_Config.bDumpFrames && startDumping)
{
avi.Stop();
osm.Show(sy->T("AVI Dump stopped."), 1.0f);
g_OSD.Show(OSDType::MESSAGE_INFO, sy->T("AVI Dump stopped."), 1.0f);
startDumping = false;
}
#endif
@ -333,17 +333,17 @@ void EmuScreen::bootGame(const Path &filename) {
if (PSP_CoreParameter().compat.flags().RequireBufferedRendering && g_Config.bSkipBufferEffects) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
System_NotifyUserMessage(gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 15.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BufferedRenderingRequired", "Warning: This game requires Rendering Mode to be set to Buffered."), 10.0f);
}
if (PSP_CoreParameter().compat.flags().RequireBlockTransfer && g_Config.bSkipGPUReadbacks) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
System_NotifyUserMessage(gr->T("BlockTransferRequired", "Warning: This game requires Simulate Block Transfer Mode to be set to On."), 15.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("BlockTransferRequired", "Warning: This game requires Simulate Block Transfer Mode to be set to On."), 10.0f);
}
if (PSP_CoreParameter().compat.flags().RequireDefaultCPUClock && g_Config.iLockedCPUSpeed != 0) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
System_NotifyUserMessage(gr->T("DefaultCPUClockRequired", "Warning: This game requires the CPU clock to be set to default."), 15.0f);
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("DefaultCPUClockRequired", "Warning: This game requires the CPU clock to be set to default."), 10.0f);
}
loadingViewColor_->Divert(0xFFFFFFFF, 0.75f);
@ -364,7 +364,7 @@ void EmuScreen::bootComplete() {
#ifndef MOBILE_DEVICE
if (g_Config.bFirstRun) {
osm.Show(sc->T("PressESC", "Press ESC to open the pause menu"), 3.0f);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("PressESC", "Press ESC to open the pause menu"));
}
#endif
@ -372,13 +372,13 @@ void EmuScreen::bootComplete() {
if (GetGPUBackend() == GPUBackend::OPENGL) {
const char *renderer = gl_extensions.model;
if (strstr(renderer, "Chainfire3D") != 0) {
osm.Show(sc->T("Chainfire3DWarning", "WARNING: Chainfire3D detected, may cause problems"), 10.0f, 0xFF30a0FF, -1, true);
g_OSD.Show(OSDType::MESSAGE_WARNING, sc->T("Chainfire3DWarning", "WARNING: Chainfire3D detected, may cause problems"), 10.0f);
} else if (strstr(renderer, "GLTools") != 0) {
osm.Show(sc->T("GLToolsWarning", "WARNING: GLTools detected, may cause problems"), 10.0f, 0xFF30a0FF, -1, true);
g_OSD.Show(OSDType::MESSAGE_WARNING, sc->T("GLToolsWarning", "WARNING: GLTools detected, may cause problems"), 10.0f);
}
if (g_Config.bGfxDebugOutput) {
osm.Show("WARNING: GfxDebugOutput is enabled via ppsspp.ini. Things may be slow.", 10.0f, 0xFF30a0FF, -1, true);
g_OSD.Show(OSDType::MESSAGE_WARNING, "WARNING: GfxDebugOutput is enabled via ppsspp.ini. Things may be slow.", 10.0f);
}
}
#endif
@ -386,9 +386,9 @@ void EmuScreen::bootComplete() {
if (Core_GetPowerSaving()) {
auto sy = GetI18NCategory(I18NCat::SYSTEM);
#ifdef __ANDROID__
osm.Show(sy->T("WARNING: Android battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
g_OSD.Show(OSDType::MESSAGE_WARNING, sy->T("WARNING: Android battery save mode is on"), 2.0f, "core_powerSaving");
#else
osm.Show(sy->T("WARNING: Battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
g_OSD.Show(OSDType::MESSAGE_WARNING, sy->T("WARNING: Battery save mode is on"), 2.0f, "core_powerSaving");
#endif
}
@ -410,7 +410,7 @@ EmuScreen::~EmuScreen() {
if (g_Config.bDumpFrames && startDumping)
{
avi.Stop();
osm.Show("AVI Dump stopped.", 1.0f);
g_OSD.Show(OSDType::MESSAGE_INFO, "AVI Dump stopped.", 2.0f);
startDumping = false;
}
#endif
@ -437,7 +437,7 @@ void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) {
static void AfterSaveStateAction(SaveState::Status status, const std::string &message, void *) {
if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) {
osm.Show(message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
}
}
@ -514,9 +514,10 @@ void EmuScreen::sendMessage(const char *message, const char *value) {
RecreateViews();
#if defined(USING_WIN_UI)
//temporary workaround for hotkey its freeze the ui when open chat screen using hotkey and native keyboard is enable
// temporary workaround for hotkey its freeze the ui when open chat screen using hotkey and native keyboard is enable
if (g_Config.bBypassOSKWithKeyboard) {
osm.Show("Disable windows native keyboard options to use ctrl + c hotkey", 2.0f);
// TODO: Make translatable.
g_OSD.Show(OSDType::MESSAGE_INFO, "Disable \"Use system native keyboard\" to use ctrl + c hotkey", 2.0f);
} else {
UI::EventParams e{};
OnChatMenu.Trigger(e);
@ -580,13 +581,13 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
// Cycle through enabled speeds.
if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) {
PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1;
osm.Show(sc->T("fixed", "Speed: alternate"), 1.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("fixed", "Speed: alternate"), 1.0);
} else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit2 >= 0) {
PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2;
osm.Show(sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0);
} else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 || PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) {
PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL;
osm.Show(sc->T("standard", "Speed: standard"), 1.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("standard", "Speed: standard"), 1.0);
}
}
break;
@ -595,12 +596,12 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
if (down) {
if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) {
PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1;
osm.Show(sc->T("fixed", "Speed: alternate"), 1.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("fixed", "Speed: alternate"), 1.0);
}
} else {
if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) {
PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL;
osm.Show(sc->T("standard", "Speed: standard"), 1.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("standard", "Speed: standard"), 1.0);
}
}
break;
@ -608,12 +609,12 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
if (down) {
if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) {
PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2;
osm.Show(sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0);
}
} else {
if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) {
PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL;
osm.Show(sc->T("standard", "Speed: standard"), 1.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("standard", "Speed: standard"), 1.0);
}
}
break;
@ -651,7 +652,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
case VIRTKEY_AXIS_SWAP:
if (down) {
controlMapper_.ToggleSwapAxes();
osm.Show(mc->T("AxisSwap")); // best string we have.
g_OSD.Show(OSDType::MESSAGE_INFO, mc->T("AxisSwap")); // best string we have.
}
break;
@ -689,7 +690,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
if (SaveState::CanRewind()) {
SaveState::Rewind(&AfterSaveStateAction);
} else {
osm.Show(sc->T("norewind", "No rewind save states available"), 2.0);
g_OSD.Show(OSDType::MESSAGE_WARNING, sc->T("norewind", "No rewind save states available"), 2.0);
}
}
break;
@ -727,10 +728,10 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
if (down) {
g_Config.bSaveNewTextures = !g_Config.bSaveNewTextures;
if (g_Config.bSaveNewTextures) {
osm.Show(sc->T("saveNewTextures_true", "Textures will now be saved to your storage"), 2.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("saveNewTextures_true", "Textures will now be saved to your storage"), 2.0);
NativeMessageReceived("gpu_configChanged", "");
} else {
osm.Show(sc->T("saveNewTextures_false", "Texture saving was disabled"), 2.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("saveNewTextures_false", "Texture saving was disabled"), 2.0);
}
}
break;
@ -738,9 +739,9 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) {
if (down) {
g_Config.bReplaceTextures = !g_Config.bReplaceTextures;
if (g_Config.bReplaceTextures)
osm.Show(sc->T("replaceTextures_true", "Texture replacement enabled"), 2.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("replaceTextures_true", "Texture replacement enabled"), 2.0);
else
osm.Show(sc->T("replaceTextures_false", "Textures no longer are being replaced"), 2.0);
g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("replaceTextures_false", "Textures no longer are being replaced"), 2.0);
NativeMessageReceived("gpu_configChanged", "");
}
break;
@ -1554,7 +1555,7 @@ bool EmuScreen::hasVisibleUI() {
// Regular but uncommon UI.
if (saveStatePreview_->GetVisibility() != UI::V_GONE || loadingSpinner_->GetVisibility() == UI::V_VISIBLE)
return true;
if (!osm.IsEmpty() || g_Config.bShowTouchControls || g_Config.iShowStatusFlags != 0)
if (!g_OSD.IsEmpty() || g_Config.bShowTouchControls || g_Config.iShowStatusFlags != 0)
return true;
if (g_Config.bEnableCardboardVR || g_Config.bEnableNetworkChat)
return true;

View File

@ -765,7 +765,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
if (!boot_filename.empty() && stateToLoad.Valid()) {
SaveState::Load(stateToLoad, -1, [](SaveState::Status status, const std::string &message, void *) {
if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) {
osm.Show(message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR,
message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
}
});
}
@ -1010,10 +1011,10 @@ void TakeScreenshot() {
bool success = TakeGameScreenshot(filename, g_Config.bScreenshotsAsPNG ? ScreenshotFormat::PNG : ScreenshotFormat::JPG, SCREENSHOT_OUTPUT);
if (success) {
osm.Show(filename.ToVisualString());
g_OSD.Show(OSDType::MESSAGE_FILE_LINK, filename.ToString());
} else {
auto err = GetI18NCategory(I18NCat::ERRORS);
osm.Show(err->T("Could not save screenshot file"));
g_OSD.Show(OSDType::MESSAGE_ERROR, err->T("Could not save screenshot file"));
}
}
@ -1140,7 +1141,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) {
auto sy = GetI18NCategory(I18NCat::SYSTEM);
std::string msg = StringFromFormat("%s: %d", sy->T("Savestate Slot"), SaveState::GetCurrentSlot() + 1);
// Show for the same duration as the preview.
osm.Show(msg, 2.0f, 0xFFFFFF, -1, true, "savestate_slot");
g_OSD.Show(OSDType::MESSAGE_INFO, msg, 2.0f, "savestate_slot");
}
else if (msg == "gpu_displayResized") {
if (gpu) {
@ -1162,9 +1163,9 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) {
if (value != "false") {
auto sy = GetI18NCategory(I18NCat::SYSTEM);
#if PPSSPP_PLATFORM(ANDROID)
osm.Show(sy->T("WARNING: Android battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
g_OSD.Show(OSDType::MESSAGE_WARNING, sy->T("WARNING: Android battery save mode is on"), 2.0f, "core_powerSaving");
#else
osm.Show(sy->T("WARNING: Battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
g_OSD.Show(OSDType::MESSAGE_WARNING, sy->T("WARNING: Battery save mode is on"), 2.0f, "core_powerSaving");
#endif
}
Core_SetPowerSaving(value != "false");
@ -1213,6 +1214,8 @@ void NativeUpdate() {
g_Discord.Update();
g_BackgroundAudio.Play();
g_OSD.Update();
UI::SetSoundEnabled(g_Config.bUISound);
}
@ -1350,10 +1353,6 @@ void System_PostUIMessage(const std::string &message, const std::string &value)
NativeMessageReceived(message.c_str(), value.c_str());
}
void System_NotifyUserMessage(const std::string &message, float duration_s, u32 color, const char *id) {
osm.Show(message, duration_s, color, -1, true, id);
}
void NativeResized() {
// NativeResized can come from any thread so we just set a flag, then process it later.
VERBOSE_LOG(G3D, "NativeResized - setting flag");

View File

@ -1,5 +1,6 @@
#include <algorithm>
#include <sstream>
#include "UI/OnScreenDisplay.h"
#include "Common/Data/Color/RGBAUtil.h"
@ -8,29 +9,24 @@
#include "Common/Render/DrawBuffer.h"
#include "Common/UI/Context.h"
#include "Common/System/System.h"
#include "Common/TimeUtil.h"
#include "Common/Net/HTTPClient.h"
#include "Core/Config.h"
OnScreenMessages osm;
void OnScreenMessagesView::Draw(UIContext &dc) {
if (!g_Config.bShowOnScreenMessages) {
return;
}
// First, clean out old messages.
osm.Lock();
osm.Clean();
// Get height
float w, h;
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, "Wg", &w, &h);
float y = 10.0f;
// Then draw them all.
const std::list<OnScreenMessages::Message> &messages = osm.Messages();
const std::vector<OnScreenDisplay::Message> messages = g_OSD.Messages();
double now = time_now_d();
for (auto iter = messages.begin(); iter != messages.end(); ++iter) {
float alpha = (iter->endTime - now) * 4.0f;
@ -62,12 +58,10 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
dc.SetFontScale(scale, scale);
}
dc.SetFontStyle(dc.theme->uiFont);
dc.DrawTextShadow(iter->text.c_str(), x, y, colorAlpha(iter->color, alpha), align);
dc.DrawTextShadow(iter->text.c_str(), x, y, colorAlpha(0xFFFFFFFF, alpha), align);
y += th * scale;
}
osm.Unlock();
// Thin bar at the top of the screen.
std::vector<float> progress = g_DownloadManager.GetCurrentProgress();
if (!progress.empty()) {
@ -92,7 +86,7 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
std::string OnScreenMessagesView::DescribeText() const {
std::stringstream ss;
const auto &messages = osm.Messages();
const auto &messages = g_OSD.Messages();
for (auto iter = messages.begin(); iter != messages.end(); ++iter) {
if (iter != messages.begin()) {
ss << "\n";
@ -102,46 +96,6 @@ std::string OnScreenMessagesView::DescribeText() const {
return ss.str();
}
void OnScreenMessages::Clean() {
restart:
double now = time_now_d();
for (auto iter = messages_.begin(); iter != messages_.end(); iter++) {
if (iter->endTime < now) {
messages_.erase(iter);
goto restart;
}
}
}
void OnScreenMessages::Show(const std::string &text, float duration_s, uint32_t color, int icon, bool checkUnique, const char *id) {
double now = time_now_d();
std::lock_guard<std::mutex> guard(mutex_);
if (checkUnique) {
for (auto iter = messages_.begin(); iter != messages_.end(); ++iter) {
if (iter->text == text || (id && iter->id && !strcmp(iter->id, id))) {
Message msg = *iter;
msg.endTime = now + duration_s;
msg.text = text;
msg.color = color;
messages_.erase(iter);
messages_.insert(messages_.begin(), msg);
return;
}
}
}
Message msg;
msg.text = text;
msg.color = color;
msg.endTime = now + duration_s;
msg.icon = icon;
msg.id = id;
messages_.insert(messages_.begin(), msg);
}
void OnScreenMessages::ShowOnOff(const std::string &message, bool b, float duration_s, uint32_t color, int icon) {
Show(message + (b ? ": on" : ": off"), duration_s, color, icon);
}
void OSDOverlayScreen::CreateViews() {
root_ = new UI::AnchorLayout();
root_->Add(new OnScreenMessagesView(new UI::AnchorLayoutParams(0.0f, 0.0f, 0.0f, 0.0f)));

View File

@ -7,40 +7,10 @@
#include "Common/Math/geom2d.h"
#include "Common/UI/View.h"
#include "Common/UI/UIScreen.h"
#include "Common/System/System.h"
class DrawBuffer;
// Data holder. This one is currently global.
class OnScreenMessages {
public:
void Show(const std::string &message, float duration_s = 1.0f, uint32_t color = 0xFFFFFF, int icon = -1, bool checkUnique = true, const char *id = nullptr);
void ShowOnOff(const std::string &message, bool b, float duration_s = 1.0f, uint32_t color = 0xFFFFFF, int icon = -1);
bool IsEmpty() const { return messages_.empty(); }
void Lock() {
mutex_.lock();
}
void Unlock() {
mutex_.unlock();
}
void Clean();
struct Message {
int icon;
uint32_t color;
std::string text;
const char *id;
double endTime;
double duration;
};
const std::list<Message> &Messages() { return messages_; }
private:
std::list<Message> messages_;
std::mutex mutex_;
};
// Infrastructure for rendering overlays.
class OnScreenMessagesView : public UI::InertView {
@ -55,5 +25,3 @@ public:
const char *tag() const override { return "OSDOverlayScreen"; }
void CreateViews() override;
};
extern OnScreenMessages osm;

View File

@ -54,7 +54,8 @@
static void AfterSaveStateAction(SaveState::Status status, const std::string &message, void *) {
if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) {
osm.Show(message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR,
message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
}
}

View File

@ -422,7 +422,7 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
}
draw_->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) {
System_NotifyUserMessage(details, 5.0, 0xFFFFFFFF, "error_callback");
g_OSD.Show(OSDType::MESSAGE_ERROR, details, 0.0f, "error_callback");
}, nullptr);
// These are auto-reset events.

View File

@ -358,7 +358,7 @@ namespace MainWindow {
static void SaveStateActionFinished(SaveState::Status status, const std::string &message, void *userdata) {
if (!message.empty() && (!g_Config.bDumpFrames || !g_Config.bDumpVideoOutput)) {
osm.Show(message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
g_OSD.Show(status == SaveState::Status::SUCCESS ? OSDType::MESSAGE_SUCCESS : OSDType::MESSAGE_ERROR, message, status == SaveState::Status::SUCCESS ? 2.0 : 5.0);
}
PostMessage(MainWindow::GetHWND(), WM_USER_SAVESTATE_FINISH, 0, 0);
}
@ -397,7 +397,7 @@ namespace MainWindow {
else
messageStream << g_Config.iFrameSkip;
osm.Show(messageStream.str());
g_OSD.Show(OSDType::MESSAGE_INFO, messageStream.str());
}
static void setFrameSkippingType(int fskipType = -1) {
@ -417,7 +417,7 @@ namespace MainWindow {
else
messageStream << gr->T("Percent of FPS");
osm.Show(messageStream.str());
g_OSD.Show(OSDType::MESSAGE_INFO, messageStream.str());
}
static void RestartApp() {
@ -507,7 +507,7 @@ namespace MainWindow {
case ID_EMULATION_CHEATS:
g_Config.bEnableCheats = !g_Config.bEnableCheats;
osm.ShowOnOff(gr->T("Cheats"), g_Config.bEnableCheats);
g_OSD.ShowOnOff(gr->T("Cheats"), g_Config.bEnableCheats);
break;
case ID_EMULATION_CHAT:
@ -677,7 +677,7 @@ namespace MainWindow {
case ID_OPTIONS_SKIP_BUFFER_EFFECTS:
g_Config.bSkipBufferEffects = !g_Config.bSkipBufferEffects;
NativeMessageReceived("gpu_renderResized", "");
osm.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects);
g_OSD.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects);
break;
case ID_DEBUG_SHOWDEBUGSTATISTICS:
@ -688,7 +688,7 @@ namespace MainWindow {
case ID_OPTIONS_HARDWARETRANSFORM:
g_Config.bHardwareTransform = !g_Config.bHardwareTransform;
NativeMessageReceived("gpu_configChanged", "");
osm.ShowOnOff(gr->T("Hardware Transform"), g_Config.bHardwareTransform);
g_OSD.ShowOnOff(gr->T("Hardware Transform"), g_Config.bHardwareTransform);
break;
case ID_OPTIONS_DISPLAY_LAYOUT:

View File

@ -946,7 +946,7 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env,
}
graphicsContext->GetDrawContext()->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) {
System_NotifyUserMessage(details, 5.0, 0xFFFFFFFF, "error_callback");
g_OSD.Show(OSDType::MESSAGE_ERROR, details, 5.0);
}, nullptr);
EmuThreadStart();
@ -962,7 +962,7 @@ extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env,
}
graphicsContext->GetDrawContext()->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) {
System_NotifyUserMessage(details, 5.0, 0xFFFFFFFF, "error_callback");
g_OSD.Show(OSDType::MESSAGE_ERROR, details, 5.0);
}, nullptr);
graphicsContext->ThreadStart();

View File

@ -1702,7 +1702,6 @@ void System_Notify(SystemNotification notification) {
}
bool System_MakeRequest(SystemRequestType type, int requestId, const std::string &param1, const std::string &param2, int param3) { return false; }
void System_PostUIMessage(const std::string &message, const std::string &param) {}
void System_NotifyUserMessage(const std::string &message, float duration, u32 color, const char *id) {}
void NativeUpdate() {}
void NativeRender(GraphicsContext *graphicsContext) {}
void NativeResized() {}

View File

@ -99,7 +99,6 @@ bool System_GetPropertyBool(SystemProperty prop) {
}
void System_Notify(SystemNotification notification) {}
void System_PostUIMessage(const std::string &message, const std::string &param) {}
void System_NotifyUserMessage(const std::string &message, float duration, u32 color, const char *id) {}
void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; }
void System_AudioClear() {}
void System_AudioPushSamples(const s32 *audio, int numSamples) {}