mirror of
https://github.com/Vita3K/Vita3K.git
synced 2024-05-31 19:17:49 -04:00
1245 lines
62 KiB
C++
1245 lines
62 KiB
C++
// Vita3K emulator project
|
|
// Copyright (C) 2023 Vita3K team
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along
|
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
#include "imgui.h"
|
|
#include "private.h"
|
|
|
|
#include <app/functions.h>
|
|
#include <audio/state.h>
|
|
#include <config/functions.h>
|
|
#include <config/state.h>
|
|
#include <display/state.h>
|
|
#include <host/dialog/filesystem.hpp>
|
|
#include <io/state.h>
|
|
#include <kernel/state.h>
|
|
#include <lang/functions.h>
|
|
#include <renderer/state.h>
|
|
#include <renderer/texture_cache.h>
|
|
|
|
#include <gui/functions.h>
|
|
#include <gui/state.h>
|
|
|
|
#include <emuenv/state.h>
|
|
|
|
#include <misc/cpp/imgui_stdlib.h>
|
|
|
|
#include <cpu/functions.h>
|
|
|
|
#include <string>
|
|
#include <util/fs.h>
|
|
#include <util/log.h>
|
|
#include <util/string_utils.h>
|
|
|
|
#include <SDL.h>
|
|
|
|
#include <algorithm>
|
|
#include <pugixml.hpp>
|
|
#include <sstream>
|
|
|
|
#undef ERROR
|
|
|
|
namespace gui {
|
|
|
|
/**
|
|
* @brief Struct used to abstract the code that manages app-specific config files
|
|
*
|
|
* This struct matches in type to the one found in `emuenv.cfg.current_config` and is
|
|
* used to collect the proper values that must be set in `emuenv.cfg.current_config`
|
|
* depending on whether an app-specific config file is being used or not.
|
|
*
|
|
* If an app-specific config file is loaded, then the values in this struct will be
|
|
* set to those of the app-specific config file before getting used to set up `emuenv.cfg.current_config`
|
|
* with those same values. If an app-specific config isn't loaded, then the values in this struct
|
|
* will be set those of the global emulator settings before getting used to set up `emuenv.cfg.current_config`.
|
|
*/
|
|
static Config::CurrentConfig config;
|
|
|
|
void get_modules_list(GuiState &gui, EmuEnvState &emuenv) {
|
|
gui.modules.clear();
|
|
|
|
const auto modules_path{ emuenv.pref_path / "vs0/sys/external/" };
|
|
if (fs::exists(modules_path) && !fs::is_empty(modules_path)) {
|
|
for (const auto &module : fs::directory_iterator(modules_path)) {
|
|
if (module.path().extension() == ".suprx")
|
|
gui.modules.push_back({ module.path().filename().replace_extension().string(), false });
|
|
}
|
|
|
|
for (auto &m : gui.modules)
|
|
m.second = std::find(config.lle_modules.begin(), config.lle_modules.end(), m.first) != config.lle_modules.end();
|
|
|
|
std::sort(gui.modules.begin(), gui.modules.end(), [](const auto &ma, const auto &mb) {
|
|
if (ma.second == mb.second)
|
|
return ma.first < mb.first;
|
|
return ma.second;
|
|
});
|
|
}
|
|
}
|
|
|
|
static void reset_emulator(GuiState &gui, EmuEnvState &emuenv) {
|
|
gui.configuration_menu.settings_dialog = false;
|
|
gui.vita_area.home_screen = false;
|
|
|
|
// Clean and save new config value
|
|
emuenv.cfg.auto_user_login = false;
|
|
emuenv.cfg.user_id.clear();
|
|
emuenv.cfg.pref_path = emuenv.pref_path.string();
|
|
emuenv.io.user_id.clear();
|
|
config::serialize_config(emuenv.cfg, emuenv.cfg.config_path);
|
|
|
|
// Clean User apps list
|
|
gui.app_selector.user_apps.clear();
|
|
|
|
get_modules_list(gui, emuenv);
|
|
get_sys_apps_title(gui, emuenv);
|
|
get_notice_list(emuenv);
|
|
get_users_list(gui, emuenv);
|
|
init_home(gui, emuenv);
|
|
}
|
|
|
|
static void change_emulator_path(GuiState &gui, EmuEnvState &emuenv) {
|
|
std::filesystem::path emulator_path = "";
|
|
host::dialog::filesystem::Result result = host::dialog::filesystem::pick_folder(emulator_path);
|
|
|
|
if (result == host::dialog::filesystem::Result::SUCCESS && emulator_path.wstring() != emuenv.pref_path.wstring()) {
|
|
// Refresh the working paths
|
|
emuenv.pref_path = emulator_path.wstring() + L'/';
|
|
|
|
// TODO: Move app old to new path
|
|
reset_emulator(gui, emuenv);
|
|
LOG_INFO("Successfully moved Vita3K path to: {}", emuenv.pref_path.string());
|
|
}
|
|
|
|
if (result == host::dialog::filesystem::Result::ERROR) {
|
|
LOG_CRITICAL("Error initializing file dialog: {}", host::dialog::filesystem::get_error());
|
|
}
|
|
}
|
|
|
|
static CPUBackend config_cpu_backend;
|
|
|
|
/**
|
|
* @brief Set up `config` with the values contained in the custom config file of a certain PlayStation Vita application
|
|
*
|
|
* If a custom config is found, the configuration values found in the file will be assigned to
|
|
* `config`.
|
|
*
|
|
* @param gui State of the Vita3K GUI
|
|
* @param emuenv State of the emulated PlayStation Vita environment
|
|
* @param app_path Path to the app or game to get the custom config for
|
|
* @return true A custom config for the application has been found, and `config` has been set up with
|
|
* the setting values contained in the custom config file.
|
|
* @return false A custom config for the application has not been found or a custom config has been found
|
|
* but it's corrupted or invalid.
|
|
*/
|
|
static bool get_custom_config(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) {
|
|
const auto CUSTOM_CONFIG_PATH{ emuenv.config_path / "config" / fmt::format("config_{}.xml", app_path) };
|
|
|
|
if (fs::exists(CUSTOM_CONFIG_PATH)) {
|
|
pugi::xml_document custom_config_xml;
|
|
if (custom_config_xml.load_file(CUSTOM_CONFIG_PATH.c_str()) && !custom_config_xml.child("config").empty()) {
|
|
config = {};
|
|
// Config
|
|
const auto config_child = custom_config_xml.child("config");
|
|
|
|
// Load Core Config
|
|
if (!config_child.child("core").empty()) {
|
|
const auto core_child = config_child.child("core");
|
|
config.modules_mode = core_child.attribute("modules-mode").as_int();
|
|
for (auto &m : core_child.child("lle-modules"))
|
|
config.lle_modules.push_back(m.text().as_string());
|
|
}
|
|
|
|
// Load CPU Config
|
|
if (!config_child.child("cpu").empty()) {
|
|
const auto cpu_child = config_child.child("cpu");
|
|
config.cpu_backend = cpu_child.attribute("cpu-backend").as_string();
|
|
config.cpu_opt = cpu_child.attribute("cpu-opt").as_bool();
|
|
}
|
|
|
|
// Load GPU Config
|
|
if (!config_child.child("gpu").empty()) {
|
|
const auto gpu_child = config_child.child("gpu");
|
|
config.high_accuracy = gpu_child.attribute("high-accuracy").as_bool();
|
|
config.resolution_multiplier = gpu_child.attribute("resolution-multiplier").as_int();
|
|
config.disable_surface_sync = gpu_child.attribute("disable-surface-sync").as_bool();
|
|
config.screen_filter = gpu_child.attribute("screen-filter").as_string();
|
|
config.v_sync = gpu_child.attribute("v-sync").as_bool();
|
|
config.anisotropic_filtering = gpu_child.attribute("anisotropic-filtering").as_int();
|
|
config.import_textures = gpu_child.attribute("import-textures").as_bool();
|
|
config.export_textures = gpu_child.attribute("export-textures").as_bool();
|
|
config.export_as_png = gpu_child.attribute("export-as-png").as_bool();
|
|
}
|
|
|
|
// Load System Config
|
|
const auto system_child = config_child.child("system");
|
|
if (!system_child.empty())
|
|
config.pstv_mode = system_child.attribute("pstv-mode").as_bool();
|
|
|
|
// Load Emulator Config
|
|
if (!config_child.child("emulator").empty()) {
|
|
const auto emulator_child = config_child.child("emulator");
|
|
config.ngs_enable = emulator_child.attribute("enable-ngs").as_bool();
|
|
config.show_touchpad_cursor = emulator_child.attribute("show-touchpad-cursor").as_bool();
|
|
}
|
|
|
|
// Load Network Config
|
|
if (!config_child.child("network").empty()) {
|
|
const auto network_child = config_child.child("network");
|
|
config.psn_signed_in = network_child.attribute("psn-signed-in").as_bool();
|
|
}
|
|
|
|
return true;
|
|
} else {
|
|
LOG_ERROR("Custom config XML found is corrupted or invalid in path: {}", CUSTOM_CONFIG_PATH.string());
|
|
fs::remove(CUSTOM_CONFIG_PATH);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static CPUBackend set_cpu_backend(std::string &cpu_backend) {
|
|
return cpu_backend == "Dynarmic" ? CPUBackend::Dynarmic : CPUBackend::Unicorn;
|
|
}
|
|
|
|
static int current_aniso_filter_log, max_aniso_filter_log, audio_backend_idx, current_user_lang;
|
|
static std::vector<std::string> list_user_lang;
|
|
|
|
/**
|
|
* @brief Initialize the `config` struct with the values set in the global emulator config.
|
|
*
|
|
* @param gui State of the Vita3K GUI
|
|
* @param emuenv State of the emulated PlayStation Vita environment
|
|
* @param app_path Path to the app or game to get the custom config for
|
|
*/
|
|
void init_config(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) {
|
|
// If no app-specific config file is being used for the initialized application,
|
|
// set up `config` with the values set in the global emulator configuration
|
|
if (!get_custom_config(gui, emuenv, app_path)) {
|
|
config.cpu_backend = emuenv.cfg.cpu_backend;
|
|
config.cpu_opt = emuenv.cfg.cpu_opt;
|
|
config.modules_mode = emuenv.cfg.modules_mode;
|
|
config.lle_modules = emuenv.cfg.lle_modules;
|
|
config.high_accuracy = emuenv.cfg.high_accuracy;
|
|
config.resolution_multiplier = emuenv.cfg.resolution_multiplier;
|
|
config.disable_surface_sync = emuenv.cfg.disable_surface_sync;
|
|
config.screen_filter = emuenv.cfg.screen_filter;
|
|
config.v_sync = emuenv.cfg.v_sync;
|
|
config.anisotropic_filtering = emuenv.cfg.anisotropic_filtering;
|
|
config.import_textures = emuenv.cfg.import_textures;
|
|
config.export_textures = emuenv.cfg.export_textures;
|
|
config.export_as_png = emuenv.cfg.export_as_png;
|
|
config.pstv_mode = emuenv.cfg.pstv_mode;
|
|
config.ngs_enable = emuenv.cfg.ngs_enable;
|
|
config.show_touchpad_cursor = emuenv.cfg.show_touchpad_cursor;
|
|
config.psn_signed_in = emuenv.cfg.psn_signed_in;
|
|
}
|
|
|
|
list_user_lang.clear();
|
|
const auto get_list_user_lang = [&](const fs::path &path) {
|
|
for (const auto &lang : fs::directory_iterator(path / "lang/user")) {
|
|
if (lang.path().extension() == ".xml") {
|
|
const auto lang_file_name = lang.path().filename().replace_extension().string();
|
|
list_user_lang.push_back(lang_file_name);
|
|
}
|
|
}
|
|
};
|
|
|
|
get_list_user_lang(emuenv.static_assets_path);
|
|
if (emuenv.static_assets_path != emuenv.shared_path)
|
|
get_list_user_lang(emuenv.shared_path);
|
|
|
|
current_user_lang = emuenv.cfg.user_lang.empty() ? 0 : (std::distance(list_user_lang.begin(), std::find(list_user_lang.begin(), list_user_lang.end(), emuenv.cfg.user_lang))) + 1;
|
|
|
|
get_modules_list(gui, emuenv);
|
|
config.stretch_the_display_area = emuenv.cfg.stretch_the_display_area;
|
|
config_cpu_backend = set_cpu_backend(config.cpu_backend);
|
|
current_aniso_filter_log = static_cast<int>(log2f(static_cast<float>(config.anisotropic_filtering)));
|
|
max_aniso_filter_log = static_cast<int>(log2f(static_cast<float>(emuenv.renderer->get_max_anisotropic_filtering())));
|
|
audio_backend_idx = (emuenv.audio.audio_backend == "SDL") ? 0 : 1;
|
|
emuenv.app_path = app_path;
|
|
emuenv.display.imgui_render = true;
|
|
}
|
|
|
|
/**
|
|
* @brief Save settings to file
|
|
*
|
|
* The function serves to save settings for both app-specific custom settings files and
|
|
* the global emulator settings file. The function automatically determines which file the
|
|
* function has to work with by detecting the kind of settings dialog the user is using
|
|
* from the GUI state.
|
|
*
|
|
* @param gui State of the Vita3K GUI
|
|
* @param emuenv State of the emulated PlayStation Vita environment
|
|
*/
|
|
static void save_config(GuiState &gui, EmuEnvState &emuenv) {
|
|
if (gui.configuration_menu.custom_settings_dialog) {
|
|
const auto CONFIG_PATH{ emuenv.config_path / "config" };
|
|
const auto CUSTOM_CONFIG_PATH{ CONFIG_PATH / fmt::format("config_{}.xml", emuenv.app_path) };
|
|
if (!fs::exists(CONFIG_PATH))
|
|
fs::create_directory(CONFIG_PATH);
|
|
|
|
pugi::xml_document custom_config_xml;
|
|
auto declarationUser = custom_config_xml.append_child(pugi::node_declaration);
|
|
declarationUser.append_attribute("version") = "1.0";
|
|
declarationUser.append_attribute("encoding") = "utf-8";
|
|
|
|
// Config
|
|
auto config_child = custom_config_xml.append_child("config");
|
|
|
|
// Core
|
|
auto core_child = config_child.append_child("core");
|
|
core_child.append_attribute("modules-mode") = config.modules_mode;
|
|
auto enable_module = core_child.append_child("lle-modules");
|
|
for (const auto &m : config.lle_modules)
|
|
enable_module.append_child("module").append_child(pugi::node_pcdata).set_value(m.c_str());
|
|
|
|
// CPU
|
|
auto cpu_child = config_child.append_child("cpu");
|
|
cpu_child.append_attribute("cpu-backend") = config.cpu_backend.c_str();
|
|
cpu_child.append_attribute("cpu-opt") = config.cpu_opt;
|
|
|
|
// GPU
|
|
auto gpu_child = config_child.append_child("gpu");
|
|
gpu_child.append_attribute("high-accuracy") = config.high_accuracy;
|
|
gpu_child.append_attribute("resolution-multiplier") = config.resolution_multiplier;
|
|
gpu_child.append_attribute("disable-surface-sync") = config.disable_surface_sync;
|
|
gpu_child.append_attribute("screen-filter") = config.screen_filter.c_str();
|
|
gpu_child.append_attribute("v-sync") = config.v_sync;
|
|
gpu_child.append_attribute("anisotropic-filtering") = config.anisotropic_filtering;
|
|
gpu_child.append_attribute("import-textures") = config.import_textures;
|
|
gpu_child.append_attribute("export-textures") = config.export_textures;
|
|
gpu_child.append_attribute("export-as-png") = config.export_as_png;
|
|
|
|
// System
|
|
auto system_child = config_child.append_child("system");
|
|
system_child.append_attribute("pstv-mode") = config.pstv_mode;
|
|
|
|
// Emulator
|
|
auto emulator_child = config_child.append_child("emulator");
|
|
emulator_child.append_attribute("enable-ngs") = config.ngs_enable;
|
|
emulator_child.append_attribute("show-touchpad-cursor") = config.show_touchpad_cursor;
|
|
|
|
// Network
|
|
auto network_child = config_child.append_child("network");
|
|
network_child.append_attribute("psn-signed-in") = config.psn_signed_in;
|
|
|
|
const auto save_xml = custom_config_xml.save_file(CUSTOM_CONFIG_PATH.c_str());
|
|
if (!save_xml)
|
|
LOG_ERROR("Failed to save custom config xml for app path: {}, in path: {}", emuenv.app_path, CONFIG_PATH.string());
|
|
} else {
|
|
emuenv.cfg.cpu_backend = config.cpu_backend;
|
|
emuenv.cfg.cpu_opt = config.cpu_opt;
|
|
emuenv.cfg.modules_mode = config.modules_mode;
|
|
emuenv.cfg.lle_modules = config.lle_modules;
|
|
emuenv.cfg.pstv_mode = config.pstv_mode;
|
|
emuenv.cfg.high_accuracy = config.high_accuracy;
|
|
emuenv.cfg.resolution_multiplier = config.resolution_multiplier;
|
|
emuenv.cfg.disable_surface_sync = config.disable_surface_sync;
|
|
emuenv.cfg.screen_filter = config.screen_filter;
|
|
emuenv.cfg.v_sync = config.v_sync;
|
|
emuenv.cfg.anisotropic_filtering = config.anisotropic_filtering;
|
|
emuenv.cfg.import_textures = config.import_textures;
|
|
emuenv.cfg.export_textures = config.export_textures;
|
|
emuenv.cfg.export_as_png = config.export_as_png;
|
|
emuenv.cfg.ngs_enable = config.ngs_enable;
|
|
emuenv.cfg.show_touchpad_cursor = config.show_touchpad_cursor;
|
|
emuenv.cfg.psn_signed_in = config.psn_signed_in;
|
|
}
|
|
|
|
if (emuenv.cfg.stretch_the_display_area != config.stretch_the_display_area) {
|
|
emuenv.cfg.stretch_the_display_area = config.stretch_the_display_area;
|
|
app::update_viewport(emuenv);
|
|
}
|
|
|
|
config::serialize_config(emuenv.cfg, emuenv.cfg.config_path);
|
|
}
|
|
|
|
std::string get_cpu_backend(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) {
|
|
if (!get_custom_config(gui, emuenv, app_path))
|
|
return emuenv.cfg.cpu_backend;
|
|
|
|
return config.cpu_backend;
|
|
}
|
|
|
|
static void set_vsync_state(const bool &state) {
|
|
if (state) {
|
|
// Try adaptive vsync first, falling back to regular vsync.
|
|
if (SDL_GL_SetSwapInterval(-1) < 0) {
|
|
SDL_GL_SetSwapInterval(1);
|
|
}
|
|
} else
|
|
SDL_GL_SetSwapInterval(0);
|
|
|
|
LOG_INFO("V-Sync state: {}", state);
|
|
}
|
|
|
|
/**
|
|
* @brief Set up the config parameters on the emulated PlayStation Vita environment
|
|
* that are susceptible to vary via app-specific config files with the proper values
|
|
* depending on whether app-specific config files are being used or not.
|
|
*
|
|
* @param gui State of the Vita3K GUI
|
|
* @param emuenv State of the emulated PlayStation Vita environment
|
|
* @param app_path Path to the app or game to get the custom config for
|
|
*/
|
|
void set_config(GuiState &gui, EmuEnvState &emuenv, const std::string &app_path) {
|
|
// If a config file is in use, call `get_custom_config()` and set the config
|
|
// parameters with the values stored in the app-specific custom config file
|
|
if (get_custom_config(gui, emuenv, app_path))
|
|
emuenv.cfg.current_config = config;
|
|
else {
|
|
// Else inherit the values from the global emulator config
|
|
emuenv.cfg.current_config.cpu_backend = emuenv.cfg.cpu_backend;
|
|
emuenv.cfg.current_config.cpu_opt = emuenv.cfg.cpu_opt;
|
|
emuenv.cfg.current_config.modules_mode = emuenv.cfg.modules_mode;
|
|
emuenv.cfg.current_config.lle_modules = emuenv.cfg.lle_modules;
|
|
emuenv.cfg.current_config.pstv_mode = emuenv.cfg.pstv_mode;
|
|
emuenv.cfg.current_config.high_accuracy = emuenv.cfg.high_accuracy;
|
|
emuenv.cfg.current_config.resolution_multiplier = emuenv.cfg.resolution_multiplier;
|
|
emuenv.cfg.current_config.disable_surface_sync = emuenv.cfg.disable_surface_sync;
|
|
emuenv.cfg.current_config.screen_filter = emuenv.cfg.screen_filter;
|
|
emuenv.cfg.current_config.v_sync = emuenv.cfg.v_sync;
|
|
emuenv.cfg.current_config.anisotropic_filtering = emuenv.cfg.anisotropic_filtering;
|
|
emuenv.cfg.current_config.import_textures = emuenv.cfg.import_textures;
|
|
emuenv.cfg.current_config.export_textures = emuenv.cfg.export_textures;
|
|
emuenv.cfg.current_config.export_as_png = emuenv.cfg.export_as_png;
|
|
emuenv.cfg.current_config.ngs_enable = emuenv.cfg.ngs_enable;
|
|
emuenv.cfg.current_config.show_touchpad_cursor = emuenv.cfg.show_touchpad_cursor;
|
|
emuenv.cfg.current_config.psn_signed_in = emuenv.cfg.psn_signed_in;
|
|
}
|
|
|
|
// If backend render or resolution multiplier is changed when app run, reboot emu and app
|
|
if (!emuenv.io.title_id.empty() && ((emuenv.renderer->current_backend != emuenv.backend_renderer) || (emuenv.renderer->res_multiplier != emuenv.cfg.current_config.resolution_multiplier))) {
|
|
emuenv.load_exec = true;
|
|
emuenv.load_app_path = emuenv.io.app_path;
|
|
emuenv.load_exec_path = emuenv.self_path;
|
|
if (!emuenv.cfg.app_args.empty())
|
|
emuenv.load_exec_argv = "\"" + emuenv.cfg.app_args + "\"";
|
|
return;
|
|
}
|
|
|
|
// can be changed while ingame
|
|
emuenv.renderer->set_surface_sync_state(emuenv.cfg.current_config.disable_surface_sync);
|
|
emuenv.renderer->set_screen_filter(emuenv.cfg.current_config.screen_filter);
|
|
if (emuenv.renderer->current_backend == renderer::Backend::OpenGL)
|
|
set_vsync_state(emuenv.cfg.current_config.v_sync);
|
|
|
|
emuenv.renderer->res_multiplier = emuenv.cfg.current_config.resolution_multiplier;
|
|
emuenv.renderer->set_anisotropic_filtering(emuenv.cfg.current_config.anisotropic_filtering);
|
|
emuenv.renderer->set_stretch_display(emuenv.cfg.stretch_the_display_area);
|
|
emuenv.renderer->get_texture_cache()->set_replacement_state(emuenv.cfg.current_config.import_textures, emuenv.cfg.current_config.export_textures, emuenv.cfg.current_config.export_as_png);
|
|
|
|
// No change it if app already running
|
|
if (emuenv.io.title_id.empty()) {
|
|
emuenv.kernel.cpu_backend = set_cpu_backend(emuenv.cfg.current_config.cpu_backend);
|
|
emuenv.kernel.cpu_opt = emuenv.cfg.current_config.cpu_opt;
|
|
emuenv.audio.set_backend(emuenv.cfg.audio_backend);
|
|
}
|
|
}
|
|
|
|
void draw_settings_dialog(GuiState &gui, EmuEnvState &emuenv) {
|
|
const ImVec2 display_size(emuenv.viewport_size.x, emuenv.viewport_size.y);
|
|
const auto RES_SCALE = ImVec2(display_size.x / emuenv.res_width_dpi_scale, display_size.y / emuenv.res_height_dpi_scale);
|
|
const auto SCALE = ImVec2(RES_SCALE.x * emuenv.dpi_scale, RES_SCALE.y * emuenv.dpi_scale);
|
|
|
|
auto &lang = gui.lang.settings_dialog;
|
|
auto &firmware_font = gui.lang.install_dialog.firmware_install;
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
ImGui::SetNextWindowPos(ImVec2(emuenv.viewport_pos.x + (display_size.x / 2.f), emuenv.viewport_pos.y + (display_size.y / 2.f)), ImGuiCond_Always, ImVec2(0.5f, 0.48f));
|
|
const auto is_custom_config = gui.configuration_menu.custom_settings_dialog;
|
|
auto &settings_dialog = is_custom_config ? gui.configuration_menu.custom_settings_dialog : gui.configuration_menu.settings_dialog;
|
|
ImGui::Begin("##settings", &settings_dialog, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
|
|
ImGui::SetWindowFontScale(0.7f * RES_SCALE.x);
|
|
auto settings_str = lang.main_window["title"].c_str();
|
|
const auto title = is_custom_config ? fmt::format("{}: {} [{}]", settings_str, get_app_index(gui, emuenv.app_path)->title, emuenv.app_path) : settings_str;
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.f) - (ImGui::CalcTextSize(title.c_str()).x / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", title.c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::BeginTabBar("SettingsTabBar", ImGuiTabBarFlags_None);
|
|
|
|
// Core
|
|
if (ImGui::BeginTabItem(lang.core["title"].c_str())) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
if (!gui.modules.empty()) {
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.core["modules_mode"].c_str());
|
|
ImGui::Spacing();
|
|
for (auto m = 0; m < MODULES_MODE_COUNT; m++) {
|
|
if (m)
|
|
ImGui::SameLine();
|
|
ImGui::RadioButton(config_modules_mode[m][ModulesModeType::MODE], &config.modules_mode, m);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", config_modules_mode[m][ModulesModeType::DESCRIPTION]);
|
|
}
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.core["modules_list"].c_str());
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.core["select_modules"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::PushItemWidth(260 * SCALE.x);
|
|
if (ImGui::BeginListBox("##modules_list", { 0.0f, ImGui::GetTextLineHeightWithSpacing() * 8.25f + ImGui::GetStyle().FramePadding.y * 2.0f })) {
|
|
for (auto &m : gui.modules) {
|
|
const auto module = std::find(config.lle_modules.begin(), config.lle_modules.end(), m.first);
|
|
const bool module_existed = (module != config.lle_modules.end());
|
|
if (!gui.module_search_bar.PassFilter(m.first.c_str()))
|
|
continue;
|
|
if (ImGui::Selectable(m.first.c_str(), &m.second, config.modules_mode == ModulesMode::AUTOMATIC ? ImGuiSelectableFlags_Disabled : ImGuiSelectableFlags_None)) {
|
|
if (module_existed)
|
|
config.lle_modules.erase(module);
|
|
else
|
|
config.lle_modules.push_back(m.first);
|
|
}
|
|
}
|
|
ImGui::EndListBox();
|
|
}
|
|
ImGui::PopItemWidth();
|
|
ImGui::Spacing();
|
|
ImGui::TextColored(GUI_COLOR_TEXT, "%s", lang.core["search_modules"].c_str());
|
|
gui.module_search_bar.Draw("##module_search_bar", 260 * SCALE.x);
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(lang.core["clear_list"].c_str())) {
|
|
config.lle_modules.clear();
|
|
for (auto &m : gui.modules)
|
|
m.second = false;
|
|
}
|
|
ImGui::SameLine();
|
|
} else {
|
|
ImGui::TextColored(GUI_COLOR_TEXT, "%s", lang.core["no_modules"].c_str());
|
|
if (ImGui::Button(gui.lang.welcome["download_firmware"].c_str()))
|
|
get_firmware_file(emuenv);
|
|
}
|
|
if (ImGui::Button(lang.core["refresh_list"].c_str()))
|
|
get_modules_list(gui, emuenv);
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
// CPU
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
if (ImGui::BeginTabItem("CPU")) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
static const char *LIST_CPU_BACKEND[] = { "Dynarmic", "Unicorn" };
|
|
static const char *LIST_CPU_BACKEND_DISPLAY[] = { "Dynarmic", "Unicorn (deprecated)" };
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.cpu["cpu_backend"].c_str());
|
|
if (ImGui::Combo("##cpu_backend", reinterpret_cast<int *>(&config_cpu_backend), LIST_CPU_BACKEND_DISPLAY, IM_ARRAYSIZE(LIST_CPU_BACKEND_DISPLAY)))
|
|
config.cpu_backend = LIST_CPU_BACKEND[int(config_cpu_backend)];
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.cpu["select_cpu_backend"].c_str());
|
|
if (config_cpu_backend == CPUBackend::Dynarmic) {
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.cpu["cpu_opt"].c_str(), &config.cpu_opt);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.cpu["cpu_opt_description"].c_str());
|
|
}
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
// GPU
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
if (ImGui::BeginTabItem("GPU")) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
|
|
#ifdef __APPLE__
|
|
ImGui::BeginDisabled();
|
|
#endif
|
|
static const char *LIST_BACKEND_RENDERER[] = { "OpenGL", "Vulkan" };
|
|
if (ImGui::Combo(lang.gpu["backend_renderer"].c_str(), reinterpret_cast<int *>(&emuenv.backend_renderer), LIST_BACKEND_RENDERER, IM_ARRAYSIZE(LIST_BACKEND_RENDERER)))
|
|
emuenv.cfg.backend_renderer = LIST_BACKEND_RENDERER[int(emuenv.backend_renderer)];
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["select_backend_renderer"].c_str());
|
|
#ifdef __APPLE__
|
|
ImGui::EndDisabled();
|
|
#else
|
|
ImGui::Spacing();
|
|
#endif
|
|
|
|
const bool is_vulkan = (emuenv.backend_renderer == renderer::Backend::Vulkan);
|
|
const bool is_ingame = !emuenv.io.title_id.empty();
|
|
if (is_vulkan) {
|
|
const std::vector<std::string> gpu_list_str = emuenv.renderer->get_gpu_list();
|
|
// must convert to a vector of char*
|
|
std::vector<const char *> gpu_list;
|
|
for (const auto &gpu : gpu_list_str)
|
|
gpu_list.push_back(gpu.c_str());
|
|
ImGui::Combo(lang.gpu["gpu"].c_str(), &emuenv.cfg.gpu_idx, gpu_list.data(), static_cast<int>(gpu_list.size()));
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["select_gpu"].c_str());
|
|
|
|
if (is_ingame)
|
|
ImGui::BeginDisabled();
|
|
|
|
static const char *LIST_RENDERER_ACCURACY[] = { "Standard", "High" };
|
|
int is_high_accuracy = static_cast<int>(config.high_accuracy);
|
|
ImGui::Combo(lang.gpu["renderer_accuracy"].c_str(), &is_high_accuracy, LIST_RENDERER_ACCURACY, IM_ARRAYSIZE(LIST_RENDERER_ACCURACY));
|
|
config.high_accuracy = static_cast<bool>(is_high_accuracy);
|
|
|
|
if (is_ingame)
|
|
ImGui::EndDisabled();
|
|
} else {
|
|
ImGui::Checkbox(lang.gpu["v_sync"].c_str(), &config.v_sync);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["v_sync_description"].c_str());
|
|
ImGui::SameLine();
|
|
}
|
|
if (!is_vulkan || emuenv.renderer->features.support_memory_mapping) {
|
|
// surface sync is supported on vulkan only when memory mapping is enabled
|
|
ImGui::Checkbox(lang.gpu["disable_surface_sync"].c_str(), &config.disable_surface_sync);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["surface_sync_description"].c_str());
|
|
}
|
|
|
|
// Screen Filter
|
|
ImGui::Spacing();
|
|
int curr_filter = 0;
|
|
const std::array<const char *, 5> possible_filters = {
|
|
"Nearest",
|
|
"Bilinear",
|
|
"Bicubic",
|
|
"FXAA",
|
|
"FSR"
|
|
};
|
|
const int filters_available = emuenv.renderer->get_supported_filters();
|
|
std::vector<const char *> filters;
|
|
for (int i = 0; i < possible_filters.size(); i++) {
|
|
if (config.screen_filter == possible_filters[i])
|
|
curr_filter = filters.size();
|
|
|
|
if ((1 << i) & filters_available)
|
|
filters.push_back(possible_filters[i]);
|
|
}
|
|
|
|
if (ImGui::Combo(lang.gpu["screen_filter"].c_str(), &curr_filter, filters.data(), filters.size()))
|
|
config.screen_filter = filters[curr_filter];
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["screen_filter_description"].c_str());
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Resolution Upscaling
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (ImGui::CalcTextSize(lang.gpu["internal_resolution_upscaling"].c_str()).x / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.gpu["internal_resolution_upscaling"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::PushID("Res scal");
|
|
if (config.resolution_multiplier == 1)
|
|
ImGui::BeginDisabled();
|
|
if (ImGui::Button("<", ImVec2(20.f * SCALE.x, 0)))
|
|
--config.resolution_multiplier;
|
|
if (config.resolution_multiplier == 1)
|
|
ImGui::EndDisabled();
|
|
ImGui::SameLine(0, 5.f * SCALE.x);
|
|
ImGui::PushItemWidth(-100.f * SCALE.x);
|
|
if (ImGui::SliderInt("##res_scal", &config.resolution_multiplier, 1, 8, fmt::format("{}x", config.resolution_multiplier).c_str(), ImGuiSliderFlags_None)) {
|
|
if (config.resolution_multiplier > 1 && !is_vulkan)
|
|
config.disable_surface_sync = true;
|
|
}
|
|
ImGui::PopItemWidth();
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["internal_resolution_upscaling_description"].c_str());
|
|
ImGui::SameLine(0, 5 * SCALE.x);
|
|
if (config.resolution_multiplier == 8)
|
|
ImGui::BeginDisabled();
|
|
if (ImGui::Button(">", ImVec2(20.f * SCALE.x, 0)))
|
|
++config.resolution_multiplier;
|
|
if (config.resolution_multiplier == 8)
|
|
ImGui::EndDisabled();
|
|
ImGui::SameLine();
|
|
if ((config.resolution_multiplier == 1) && !config.disable_surface_sync)
|
|
ImGui::BeginDisabled();
|
|
if (ImGui::Button(lang.gpu["reset"].c_str(), ImVec2(60.f * SCALE.x, 0)))
|
|
config.resolution_multiplier = 1;
|
|
|
|
if ((config.resolution_multiplier == 1) && !config.disable_surface_sync)
|
|
ImGui::EndDisabled();
|
|
ImGui::Spacing();
|
|
const auto res_scal = fmt::format("{}x{}", 960 * config.resolution_multiplier, 544 * config.resolution_multiplier);
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (ImGui::CalcTextSize(res_scal.c_str()).x / 2.f) - (35.f * SCALE.x));
|
|
ImGui::Text("%s", res_scal.c_str());
|
|
ImGui::PopID();
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Anisotropic Filtering
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (ImGui::CalcTextSize(lang.gpu["anisotropic_filtering"].c_str()).x / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.gpu["anisotropic_filtering"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::PushID("Aniso filter");
|
|
if (config.anisotropic_filtering == 1)
|
|
ImGui::BeginDisabled();
|
|
if (ImGui::Button("<", ImVec2(20.f * SCALE.x, 0)))
|
|
config.anisotropic_filtering = 1 << --current_aniso_filter_log;
|
|
if (config.anisotropic_filtering == 1)
|
|
ImGui::EndDisabled();
|
|
ImGui::SameLine(0, 5 * SCALE.x);
|
|
ImGui::PushItemWidth(-100.f * SCALE.x);
|
|
if (ImGui::SliderInt("##aniso_filter", ¤t_aniso_filter_log, 0, max_aniso_filter_log, fmt::format("{}x", config.anisotropic_filtering).c_str()))
|
|
config.anisotropic_filtering = 1 << current_aniso_filter_log;
|
|
ImGui::PopItemWidth();
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["anisotropic_filtering_description"].c_str());
|
|
ImGui::SameLine(0, 5 * SCALE.x);
|
|
if (current_aniso_filter_log == max_aniso_filter_log)
|
|
ImGui::BeginDisabled();
|
|
if (ImGui::Button(">", ImVec2(20.f * SCALE.x, 0)))
|
|
config.anisotropic_filtering = 1 << ++current_aniso_filter_log;
|
|
if (current_aniso_filter_log == max_aniso_filter_log)
|
|
ImGui::EndDisabled();
|
|
ImGui::SameLine();
|
|
if (config.anisotropic_filtering == 1)
|
|
ImGui::BeginDisabled();
|
|
if (ImGui::Button(lang.gpu["reset"].c_str(), ImVec2(60.f * SCALE.x, 0))) {
|
|
config.anisotropic_filtering = 1;
|
|
current_aniso_filter_log = 0;
|
|
}
|
|
if (config.anisotropic_filtering == 1)
|
|
ImGui::EndDisabled();
|
|
ImGui::PopID();
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Texture Replacement
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (ImGui::CalcTextSize(lang.gpu["texture_replacement"].c_str()).x / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.gpu["texture_replacement"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.gpu["export_textures"].c_str(), &config.export_textures);
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.gpu["import_textures"].c_str(), &config.import_textures);
|
|
|
|
static const char *export_formats[] = { "PNG", "DDS" };
|
|
int export_format_pos = config.export_as_png ? 0 : 1;
|
|
if (ImGui::Combo(lang.gpu["texture_exporting_format"].c_str(), &export_format_pos, export_formats, IM_ARRAYSIZE(export_formats)))
|
|
config.export_as_png = export_format_pos == 0;
|
|
|
|
// Shaders
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (ImGui::CalcTextSize(lang.gpu["shaders"].c_str()).x / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.gpu["shaders"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.gpu["shader_cache"].c_str(), &emuenv.cfg.shader_cache);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gpu["shader_cache_description"].c_str());
|
|
if (emuenv.renderer->features.spirv_shader) {
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.gpu["spirv_shader"].c_str(), &emuenv.cfg.spirv_shader);
|
|
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::SetTooltip("%s", lang.gpu["spirv_shader_description"].c_str());
|
|
}
|
|
}
|
|
const auto shaders_cache_path{ emuenv.cache_path / "shaders" };
|
|
if (fs::exists(shaders_cache_path) && !fs::is_empty(shaders_cache_path)) {
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(lang.gpu["clean_shaders"].c_str())) {
|
|
fs::remove_all(shaders_cache_path);
|
|
fs::remove_all(emuenv.cache_path / "shaderlog");
|
|
}
|
|
}
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
// System
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
if (ImGui::BeginTabItem(lang.system["title"].c_str())) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
ImGui::TextColored(GUI_COLOR_TEXT, "%s", lang.system["select_enter_button"].c_str());
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.system["enter_button_description"].c_str());
|
|
ImGui::RadioButton(lang.system["circle"].c_str(), &emuenv.cfg.sys_button, 0);
|
|
ImGui::RadioButton(lang.system["cross"].c_str(), &emuenv.cfg.sys_button, 1);
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.system["pstv_mode"].c_str(), &config.pstv_mode);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.system["pstv_mode_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.system["show_mode"].c_str(), &emuenv.cfg.show_mode);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.system["show_mode_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.system["demo_mode"].c_str(), &emuenv.cfg.demo_mode);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.system["demo_mode_description"].c_str());
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
// Emulator
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
if (ImGui::BeginTabItem(lang.emulator["title"].c_str())) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.emulator["boot_apps_full_screen"].c_str(), &emuenv.cfg.boot_apps_full_screen);
|
|
ImGui::Spacing();
|
|
|
|
if (!emuenv.io.app_path.empty())
|
|
ImGui::BeginDisabled();
|
|
|
|
static const char *LIST_BACKEND_AUDIO[] = { "SDL", "Cubeb" };
|
|
if (ImGui::Combo(lang.emulator["audio_backend"].c_str(), reinterpret_cast<int *>(&audio_backend_idx), LIST_BACKEND_AUDIO, IM_ARRAYSIZE(LIST_BACKEND_AUDIO)))
|
|
emuenv.cfg.audio_backend = LIST_BACKEND_AUDIO[audio_backend_idx];
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["select_audio_backend"].c_str());
|
|
|
|
if (!emuenv.io.app_path.empty())
|
|
ImGui::EndDisabled();
|
|
|
|
ImGui::Checkbox(lang.emulator["enable_ngs_support"].c_str(), &config.ngs_enable);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["ngs_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
if (ImGui::Combo(lang.emulator["log_level"].c_str(), &emuenv.cfg.log_level, "Trace\0Debug\0Info\0Warning\0Error\0Critical\0Off\0"))
|
|
logging::set_level(static_cast<spdlog::level::level_enum>(emuenv.cfg.log_level));
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["select_log_level"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.emulator["archive_log"].c_str(), &emuenv.cfg.archive_log);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["archive_log_description"].c_str());
|
|
ImGui::SameLine();
|
|
#ifdef USE_DISCORD
|
|
ImGui::Checkbox("Discord Rich Presence", &emuenv.cfg.discord_rich_presence);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["discord_rich_presence"].c_str());
|
|
#endif
|
|
ImGui::Checkbox(lang.emulator["texture_cache"].c_str(), &emuenv.cfg.texture_cache);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["texture_cache_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.emulator["show_compile_shaders"].c_str(), &emuenv.cfg.show_compile_shaders);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["compile_shaders_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.emulator["show_touchpad_cursor"].c_str(), &config.show_touchpad_cursor);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["touchpad_cursor_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.emulator["log_compat_warn"].c_str(), &emuenv.cfg.log_compat_warn);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["log_compat_warn_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.emulator["check_for_updates"].c_str(), &emuenv.cfg.check_for_updates);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["check_for_updates_description"].c_str());
|
|
ImGui::Separator();
|
|
const auto perfomance_overley_size = ImGui::CalcTextSize(lang.emulator["performance_overlay"].c_str()).x;
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (perfomance_overley_size / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.emulator["performance_overlay"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.emulator["performance_overlay"].c_str(), &emuenv.cfg.performance_overlay);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["performance_overlay_description"].c_str());
|
|
if (emuenv.cfg.performance_overlay) {
|
|
ImGui::Combo(lang.emulator["detail"].c_str(), &emuenv.cfg.performance_overlay_detail, "Minimum\0Low\0Medium\0Maximum\0");
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["select_detail"].c_str());
|
|
ImGui::Combo(lang.emulator["position"].c_str(), &emuenv.cfg.performance_overlay_position, "Top Left\0Top Center\0Top Right\0Bottom Left\0Bottom Center\0Bottom Right\0");
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["select_position"].c_str());
|
|
}
|
|
ImGui::Spacing();
|
|
#ifndef WIN32
|
|
ImGui::Checkbox(lang.emulator["case_insensitive"].c_str(), &emuenv.io.case_isens_find_enabled);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["case_insensitive_description"].c_str());
|
|
#endif
|
|
ImGui::Separator();
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (ImGui::CalcTextSize(lang.emulator["emu_storage_folder"].c_str()).x / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.emulator["emu_storage_folder"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::PushItemWidth(320);
|
|
ImGui::TextColored(GUI_COLOR_TEXT, "%s %s", lang.emulator["current_emu_path"].c_str(), emuenv.cfg.pref_path.c_str());
|
|
ImGui::PopItemWidth();
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(lang.emulator["change_emu_path"].c_str()))
|
|
change_emulator_path(gui, emuenv);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["change_emu_path_description"].c_str());
|
|
if (emuenv.cfg.pref_path != emuenv.default_path) {
|
|
ImGui::SameLine();
|
|
if (ImGui::Button(lang.emulator["reset_emu_path"].c_str())) {
|
|
if (emuenv.default_path != emuenv.pref_path) {
|
|
emuenv.pref_path = emuenv.default_path;
|
|
|
|
// Refresh the working paths
|
|
reset_emulator(gui, emuenv);
|
|
LOG_INFO("Successfully restored default path for Vita3K files to: {}", emuenv.pref_path.string());
|
|
}
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.emulator["reset_emu_path_description"].c_str());
|
|
}
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (ImGui::CalcTextSize(lang.emulator["custom_config_settings"].c_str()).x / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "%s", lang.emulator["custom_config_settings"].c_str());
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(lang.emulator["clear_custom_config"].c_str())) {
|
|
if (fs::remove_all(emuenv.config_path / "config")) {
|
|
LOG_INFO("Clear all custom config settings successfully.");
|
|
}
|
|
}
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
// GUI
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
if (ImGui::BeginTabItem(lang.gui["title"].c_str())) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.gui["show_gui"].c_str(), &emuenv.cfg.show_gui);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["gui_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.gui["show_info_bar"].c_str(), &emuenv.cfg.show_info_bar);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["info_bar_description"].c_str());
|
|
ImGui::Spacing();
|
|
std::vector<const char *> list_user_lang_str{ fmt::format("System: {}", get_sys_lang_name(emuenv.cfg.sys_lang)).c_str() };
|
|
static std::map<std::string, std::string> static_list_user_lang_names = {
|
|
{ "id", "Indonesia" },
|
|
{ "ms", "Malaysia" },
|
|
};
|
|
for (const auto &l : list_user_lang)
|
|
list_user_lang_str.push_back(static_list_user_lang_names.contains(l) ? static_list_user_lang_names[l].c_str() : l.c_str());
|
|
if (ImGui::Combo(lang.gui["user_lang"].c_str(), ¤t_user_lang, list_user_lang_str.data(), static_cast<int>(list_user_lang_str.size()), 4)) {
|
|
if (current_user_lang != 0)
|
|
emuenv.cfg.user_lang = list_user_lang[current_user_lang - 1];
|
|
else
|
|
emuenv.cfg.user_lang.clear();
|
|
|
|
lang::init_lang(gui.lang, emuenv);
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["select_user_lang"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.gui["display_info_message"].c_str(), &emuenv.cfg.display_info_message);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["display_info_message_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.gui["display_system_apps"].c_str(), &emuenv.cfg.display_system_apps);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["display_system_apps_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.gui["show_live_area_screen"].c_str(), &emuenv.cfg.show_live_area_screen);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["live_area_screen_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.gui["stretch_the_display_area"].c_str(), &config.stretch_the_display_area);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["stretch_the_display_area_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.gui["apps_list_grid"].c_str(), &emuenv.cfg.apps_list_grid);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["apps_list_grid_description"].c_str());
|
|
if (!emuenv.cfg.apps_list_grid) {
|
|
ImGui::Spacing();
|
|
ImGui::SliderInt(lang.gui["icon_size"].c_str(), &emuenv.cfg.icon_size, 64, 128);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["select_icon_size"].c_str());
|
|
}
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
const auto font_size = ImGui::CalcTextSize(lang.gui["font_support"].c_str()).x;
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (font_size / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_MENUBAR, "%s", lang.gui["font_support"].c_str());
|
|
ImGui::Spacing();
|
|
if (gui.fw_font) {
|
|
ImGui::Checkbox(lang.gui["asia_font_support"].c_str(), &emuenv.cfg.asia_font_support);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["asia_font_support_description"].c_str());
|
|
} else {
|
|
ImGui::TextColored(GUI_COLOR_TEXT, "%s", firmware_font["no_font_exist"].c_str());
|
|
if (ImGui::Button(firmware_font["download_firmware_font_package"].c_str()))
|
|
open_path("https://bit.ly/2P2rb0r");
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["firmware_font_package_description"].c_str());
|
|
}
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
const auto title = ImGui::CalcTextSize(lang.gui["theme_background"].c_str()).x;
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (title / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_MENUBAR, "%s", lang.gui["theme_background"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::TextColored(GUI_COLOR_TEXT, "%s %s", lang.gui["current_theme_content_id"].c_str(), gui.users[emuenv.io.user_id].theme_id.c_str());
|
|
if (gui.users[emuenv.io.user_id].theme_id != "default") {
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(lang.gui["reset_default_theme"].c_str())) {
|
|
gui.users[emuenv.io.user_id].theme_id = "default";
|
|
gui.users[emuenv.io.user_id].use_theme_bg = false;
|
|
if (init_theme(gui, emuenv, "default"))
|
|
gui.users[emuenv.io.user_id].use_theme_bg = true;
|
|
gui.users[emuenv.io.user_id].start_path.clear();
|
|
gui.users[emuenv.io.user_id].start_type = "default";
|
|
save_user(gui, emuenv, emuenv.io.user_id);
|
|
init_theme_start_background(gui, emuenv, "default");
|
|
init_apps_icon(gui, emuenv, gui.app_selector.sys_apps);
|
|
}
|
|
ImGui::SameLine();
|
|
}
|
|
if (!gui.theme_backgrounds.empty())
|
|
if (ImGui::Checkbox(lang.gui["using_theme_background"].c_str(), &gui.users[emuenv.io.user_id].use_theme_bg))
|
|
save_user(gui, emuenv, emuenv.io.user_id);
|
|
|
|
if (!gui.user_backgrounds.empty()) {
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(lang.gui["clean_user_backgrounds"].c_str())) {
|
|
gui.user_backgrounds[gui.users[emuenv.io.user_id].backgrounds[gui.current_user_bg]] = {};
|
|
gui.user_backgrounds.clear();
|
|
if (!gui.theme_backgrounds.empty())
|
|
gui.users[emuenv.io.user_id].use_theme_bg = true;
|
|
gui.users[emuenv.io.user_id].backgrounds.clear();
|
|
save_user(gui, emuenv, emuenv.io.user_id);
|
|
}
|
|
}
|
|
ImGui::Spacing();
|
|
ImGui::TextColored(GUI_COLOR_TEXT, "%s %s", lang.gui["current_start_background"].c_str(), gui.users[emuenv.io.user_id].start_type.c_str());
|
|
if (((gui.users[emuenv.io.user_id].theme_id == "default") && (gui.users[emuenv.io.user_id].start_type != "default")) || ((gui.users[emuenv.io.user_id].theme_id != "default") && (gui.users[emuenv.io.user_id].start_type != "theme"))) {
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(lang.gui["reset_start_background"].c_str())) {
|
|
gui.users[emuenv.io.user_id].start_path.clear();
|
|
init_theme_start_background(gui, emuenv, gui.users[emuenv.io.user_id].theme_id);
|
|
gui.users[emuenv.io.user_id].start_type = (gui.users[emuenv.io.user_id].theme_id == "default") ? "default" : "theme";
|
|
save_user(gui, emuenv, emuenv.io.user_id);
|
|
}
|
|
}
|
|
if (!gui.theme_backgrounds.empty() || !gui.user_backgrounds.empty()) {
|
|
ImGui::Spacing();
|
|
ImGui::SliderFloat(lang.gui["background_alpha"].c_str(), &emuenv.cfg.background_alpha, 0.999f, 0.000f);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["select_background_alpha"].c_str());
|
|
}
|
|
if (!gui.theme_backgrounds.empty() || (gui.user_backgrounds.size() > 1)) {
|
|
ImGui::Spacing();
|
|
ImGui::SliderInt(lang.gui["delay_background"].c_str(), &emuenv.cfg.delay_background, 4, 60);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["select_delay_background"].c_str());
|
|
}
|
|
ImGui::Spacing();
|
|
ImGui::SliderInt(lang.gui["delay_start"].c_str(), &emuenv.cfg.delay_start, 10, 60);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.gui["select_delay_start"].c_str());
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
// Network
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
if (ImGui::BeginTabItem(lang.network["title"].c_str())) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
|
|
// PSN
|
|
const auto psn = ImGui::CalcTextSize("PlayStation Network").x;
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (psn / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_MENUBAR, "PlayStation Network");
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.network["psn_signed_in"].c_str(), &config.psn_signed_in);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.network["psn_signed_in_description"].c_str());
|
|
|
|
// HTTP
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
const auto http = ImGui::CalcTextSize("HTTP").x;
|
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() / 2.f) - (http / 2.f));
|
|
ImGui::TextColored(GUI_COLOR_TEXT_MENUBAR, "HTTP");
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.network["enable_http"].c_str(), &emuenv.cfg.http_enable);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.network["enable_http_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::SliderInt(lang.network["timeout_attempts"].c_str(), &emuenv.cfg.http_timeout_attempts, 0, 100);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.network["timeout_attempts_description"].c_str());
|
|
ImGui::SliderInt(lang.network["timeout_sleep"].c_str(), &emuenv.cfg.http_timeout_sleep_ms, 50, 3000);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.network["timeout_sleep_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
ImGui::SliderInt(lang.network["read_end_attempts"].c_str(), &emuenv.cfg.http_read_end_attempts, 0, 100);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.network["read_end_attempts_description"].c_str());
|
|
ImGui::SliderInt(lang.network["read_end_sleep"].c_str(), &emuenv.cfg.http_read_end_sleep_ms, 50, 3000);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.network["read_end_sleep_description"].c_str());
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
// Debug
|
|
ImGui::PushStyleColor(ImGuiCol_Text, GUI_COLOR_TEXT_MENUBAR);
|
|
if (ImGui::BeginTabItem("Debug")) {
|
|
ImGui::PopStyleColor();
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.debug["log_imports"].c_str(), &emuenv.kernel.debugger.log_imports);
|
|
ImGui::SameLine();
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.debug["log_imports_description"].c_str());
|
|
ImGui::Checkbox(lang.debug["log_exports"].c_str(), &emuenv.kernel.debugger.log_exports);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.debug["log_exports_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.debug["log_active_shaders"].c_str(), &emuenv.cfg.log_active_shaders);
|
|
ImGui::SameLine();
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.debug["log_active_shaders_description"].c_str());
|
|
ImGui::Checkbox(lang.debug["log_uniforms"].c_str(), &emuenv.cfg.log_uniforms);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.debug["log_uniforms_description"].c_str());
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(lang.debug["color_surface_debug"].c_str(), &emuenv.cfg.color_surface_debug);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.debug["color_surface_debug_description"].c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Checkbox(lang.debug["dump_elfs"].c_str(), &emuenv.kernel.debugger.dump_elfs);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.debug["dump_elfs_description"].c_str());
|
|
ImGui::SameLine();
|
|
if (emuenv.backend_renderer == renderer::Backend::Vulkan) {
|
|
ImGui::Checkbox(lang.debug["validation_layer"].c_str(), &emuenv.cfg.validation_layer);
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.debug["validation_layer_description"].c_str());
|
|
ImGui::Spacing();
|
|
}
|
|
if (ImGui::Button(emuenv.kernel.debugger.watch_code ? lang.debug["unwatch_code"].c_str() : lang.debug["watch_code"].c_str())) {
|
|
emuenv.kernel.debugger.watch_code = !emuenv.kernel.debugger.watch_code;
|
|
emuenv.kernel.debugger.update_watches();
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button(emuenv.kernel.debugger.watch_memory ? lang.debug["unwatch_memory"].c_str() : lang.debug["watch_memory"].c_str())) {
|
|
emuenv.kernel.debugger.watch_memory = !emuenv.kernel.debugger.watch_memory;
|
|
emuenv.kernel.debugger.update_watches();
|
|
}
|
|
ImGui::Spacing();
|
|
if (ImGui::Button(emuenv.kernel.debugger.watch_import_calls ? lang.debug["unwatch_import_calls"].c_str() : lang.debug["watch_import_calls"].c_str())) {
|
|
emuenv.kernel.debugger.watch_import_calls = !emuenv.kernel.debugger.watch_import_calls;
|
|
emuenv.kernel.debugger.update_watches();
|
|
}
|
|
|
|
#ifdef TRACY_ENABLE
|
|
// Tracy profiler settings
|
|
ImGui::Spacing();
|
|
ImGui::TextColored(GUI_COLOR_TEXT_TITLE, "Tracy Profiler");
|
|
|
|
ImGui::Text("The Tracy profiler implementation in the emulator allows among other\n"
|
|
"things to track the functions that a game calls in real-time\n"
|
|
"and visualize them in a timeline with timings for every frame and audio buffer.");
|
|
|
|
// Primitive Tracy implementation
|
|
ImGui::Checkbox("Primitive implementation", &emuenv.cfg.tracy_primitive_impl);
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::SetTooltip("The primitive Tracy implementation for HLE modules allows for\n"
|
|
"all HLE module calls to be logged without manual instrumentation needed.\n"
|
|
"However it is just a general workaround that doesn't count for statistic\n"
|
|
"analysis neither for trace searching on Tracy.\n\n"
|
|
"Due to the amount of functions being logged due to this implementation\n"
|
|
"Tracy logs can become gigabytes long in a matter of minutes. Because of this\n"
|
|
"it is only recommended to be used when the module(s) to debug aren't available for\n"
|
|
"advanced profiling or a more general overview of the function calls is needed and\n"
|
|
"in a PC with at least 12GB (Linux) or 16GB (Windows) of RAM.");
|
|
}
|
|
|
|
// ImGui::Text("The Tracy profiler is not available in Release builds, please compile Vita3K\nfrom source using"
|
|
// " either the RelWithDebInfo or Debug builds in order to use it.");
|
|
|
|
// Text to display along the modules list
|
|
const std::string tracy_modules_list_label = "Available modules for advanced profiling\n\n"
|
|
"Modules enabled for advanced profiling don't\n"
|
|
"only provide function call timings but\n"
|
|
"also log the arguments they were called\n"
|
|
"with for every single function call\n"
|
|
"except arguments driving a large amount\n"
|
|
"of data such as large sized arrays.\n\n"
|
|
"Advanced profiling requires functions to\n"
|
|
"be manually instrumented in source code.";
|
|
|
|
// Tracy modules list
|
|
if (ImGui::BeginListBox(tracy_modules_list_label.c_str(), { 0.0f, ImGui::GetTextLineHeightWithSpacing() * 8.25f + ImGui::GetStyle().FramePadding.y * 2.0f })) {
|
|
// Get all HLE modules available for advanced profiling using Tracy. Do it only once.
|
|
static std::vector<std::string> tracy_modules = tracy_module_utils::get_available_module_names();
|
|
// For every HLE module available for advanced profiling using Tracy
|
|
for (auto &module : tracy_modules) {
|
|
bool activation_state = tracy_module_utils::is_tracy_active(module);
|
|
// Create selectable item using module name and get activation state
|
|
if (ImGui::Selectable(module.c_str(), activation_state)) {
|
|
// Change activation state if module is clicked/selected
|
|
if (activation_state == true) {
|
|
// Deactivate module
|
|
tracy_module_utils::set_tracy_active(module, false);
|
|
// Update config data by deleting the name of the module from the vector
|
|
std::erase(emuenv.cfg.tracy_advanced_profiling_modules, module);
|
|
} else {
|
|
// Activate module
|
|
tracy_module_utils::set_tracy_active(module, true);
|
|
// Update config data by appending the name of the module to the vector
|
|
emuenv.cfg.tracy_advanced_profiling_modules.push_back(module);
|
|
}
|
|
}
|
|
}
|
|
ImGui::EndListBox();
|
|
}
|
|
#endif // TRACY_ENABLE
|
|
|
|
ImGui::EndTabItem();
|
|
} else
|
|
ImGui::PopStyleColor();
|
|
|
|
ImGui::EndTabBar();
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
static const auto BUTTON_SIZE = ImVec2(120.f * SCALE.x, 0.f);
|
|
ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.f) - BUTTON_SIZE.x - (10.f * SCALE.x));
|
|
if (ImGui::Button(lang.main_window["close"].c_str(), BUTTON_SIZE))
|
|
settings_dialog = false;
|
|
ImGui::SameLine(0, 20.f * SCALE.x);
|
|
const auto is_apply = !emuenv.io.app_path.empty() && (!is_custom_config || (emuenv.app_path == emuenv.io.app_path));
|
|
const auto is_reboot = (emuenv.renderer->current_backend != emuenv.backend_renderer) || (config.resolution_multiplier != emuenv.cfg.current_config.resolution_multiplier);
|
|
if (ImGui::Button(is_apply ? (is_reboot ? lang.main_window["save_reboot"].c_str() : lang.main_window["save_apply"].c_str()) : lang.main_window["save"].c_str(), BUTTON_SIZE)) {
|
|
save_config(gui, emuenv);
|
|
if (is_apply)
|
|
set_config(gui, emuenv, emuenv.io.app_path);
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", lang.main_window["keep_changes"].c_str());
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
} // namespace gui
|