2015-01-04 09:36:57 -08:00
|
|
|
// Copyright 2014 Citra Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2016-12-15 01:56:32 -08:00
|
|
|
#include <cinttypes>
|
2016-03-06 05:04:47 -08:00
|
|
|
#include <clocale>
|
2016-04-05 05:29:55 -07:00
|
|
|
#include <memory>
|
2014-10-28 00:36:00 -07:00
|
|
|
#include <thread>
|
2019-08-13 12:42:22 -07:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <unistd.h> // for chdir
|
|
|
|
#endif
|
2018-08-15 02:38:37 -07:00
|
|
|
|
2018-09-19 19:09:23 -07:00
|
|
|
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
|
2019-03-11 16:39:48 -07:00
|
|
|
#include "applets/error.h"
|
2018-11-22 18:00:42 -08:00
|
|
|
#include "applets/profile_select.h"
|
2018-11-09 17:38:11 -08:00
|
|
|
#include "applets/software_keyboard.h"
|
2018-12-24 13:23:31 -08:00
|
|
|
#include "applets/web_browser.h"
|
2019-03-06 10:31:23 -08:00
|
|
|
#include "configuration/configure_input.h"
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
#include "configuration/configure_per_game.h"
|
2018-09-19 19:09:23 -07:00
|
|
|
#include "core/file_sys/vfs.h"
|
|
|
|
#include "core/file_sys/vfs_real.h"
|
2019-03-11 16:39:48 -07:00
|
|
|
#include "core/frontend/applets/general_frontend.h"
|
2018-10-10 18:49:20 -07:00
|
|
|
#include "core/hle/service/acc/profile_manager.h"
|
2019-09-21 19:46:53 -07:00
|
|
|
#include "core/hle/service/am/applet_ae.h"
|
|
|
|
#include "core/hle/service/am/applet_oe.h"
|
2018-11-09 17:38:11 -08:00
|
|
|
#include "core/hle/service/am/applets/applets.h"
|
2018-12-24 13:23:31 -08:00
|
|
|
#include "core/hle/service/hid/controllers/npad.h"
|
|
|
|
#include "core/hle/service/hid/hid.h"
|
2018-09-19 19:09:23 -07:00
|
|
|
|
2018-11-13 06:06:41 -08:00
|
|
|
// These are wrappers to avoid the calls to CreateDirectory and CreateFile because of the Windows
|
2018-09-19 19:09:23 -07:00
|
|
|
// defines.
|
|
|
|
static FileSys::VirtualDir VfsFilesystemCreateDirectoryWrapper(
|
|
|
|
const FileSys::VirtualFilesystem& vfs, const std::string& path, FileSys::Mode mode) {
|
|
|
|
return vfs->CreateDirectory(path, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::VirtualDir& dir,
|
|
|
|
const std::string& path) {
|
|
|
|
return dir->CreateFile(path);
|
|
|
|
}
|
|
|
|
|
2018-08-15 02:38:37 -07:00
|
|
|
#include <fmt/ostream.h>
|
2016-03-18 18:31:01 -07:00
|
|
|
#include <glad/glad.h>
|
2018-08-15 02:38:37 -07:00
|
|
|
|
2016-03-18 18:31:01 -07:00
|
|
|
#define QT_NO_OPENGL
|
2019-04-04 08:29:16 -07:00
|
|
|
#include <QClipboard>
|
|
|
|
#include <QDesktopServices>
|
2014-03-31 19:26:50 -07:00
|
|
|
#include <QDesktopWidget>
|
2018-09-03 16:23:10 -07:00
|
|
|
#include <QDialogButtonBox>
|
2018-10-24 06:37:29 -07:00
|
|
|
#include <QFile>
|
2014-03-31 19:26:50 -07:00
|
|
|
#include <QFileDialog>
|
2019-04-04 08:29:16 -07:00
|
|
|
#include <QInputDialog>
|
2015-07-28 09:43:18 -07:00
|
|
|
#include <QMessageBox>
|
2019-04-04 08:29:16 -07:00
|
|
|
#include <QProgressBar>
|
|
|
|
#include <QProgressDialog>
|
|
|
|
#include <QShortcut>
|
|
|
|
#include <QStatusBar>
|
2019-09-21 05:24:16 -07:00
|
|
|
#include <QSysInfo>
|
2020-06-20 21:09:28 -07:00
|
|
|
#include <QUrl>
|
2018-09-23 18:06:33 -07:00
|
|
|
#include <QtConcurrent/QtConcurrent>
|
2019-04-04 08:29:16 -07:00
|
|
|
|
2018-08-29 06:42:53 -07:00
|
|
|
#include <fmt/format.h>
|
2018-06-14 14:25:40 -07:00
|
|
|
#include "common/common_paths.h"
|
2018-09-16 11:05:51 -07:00
|
|
|
#include "common/detached_tasks.h"
|
2018-09-02 07:53:06 -07:00
|
|
|
#include "common/file_util.h"
|
2016-09-17 17:38:01 -07:00
|
|
|
#include "common/logging/backend.h"
|
|
|
|
#include "common/logging/filter.h"
|
|
|
|
#include "common/logging/log.h"
|
2020-05-17 11:45:12 -07:00
|
|
|
#include "common/memory_detect.h"
|
2015-08-17 14:25:21 -07:00
|
|
|
#include "common/microprofile.h"
|
2015-06-21 06:58:59 -07:00
|
|
|
#include "common/scm_rev.h"
|
2014-10-28 00:36:00 -07:00
|
|
|
#include "common/scope_exit.h"
|
2019-09-21 05:24:16 -07:00
|
|
|
#ifdef ARCHITECTURE_x86_64
|
|
|
|
#include "common/x64/cpu_detect.h"
|
|
|
|
#endif
|
2018-08-31 09:21:34 -07:00
|
|
|
#include "common/telemetry.h"
|
2016-09-17 17:38:01 -07:00
|
|
|
#include "core/core.h"
|
2018-07-28 18:39:42 -07:00
|
|
|
#include "core/crypto/key_manager.h"
|
2018-08-09 18:33:13 -07:00
|
|
|
#include "core/file_sys/card_image.h"
|
2018-09-03 18:58:19 -07:00
|
|
|
#include "core/file_sys/content_archive.h"
|
2018-09-04 14:01:40 -07:00
|
|
|
#include "core/file_sys/control_metadata.h"
|
|
|
|
#include "core/file_sys/patch_manager.h"
|
2018-08-20 17:36:36 -07:00
|
|
|
#include "core/file_sys/registered_cache.h"
|
2018-09-19 19:09:23 -07:00
|
|
|
#include "core/file_sys/romfs.h"
|
2018-08-20 21:46:40 -07:00
|
|
|
#include "core/file_sys/savedata_factory.h"
|
2018-09-04 11:44:40 -07:00
|
|
|
#include "core/file_sys/submission_package.h"
|
2018-11-11 13:41:31 -08:00
|
|
|
#include "core/frontend/applets/software_keyboard.h"
|
2018-09-04 11:44:40 -07:00
|
|
|
#include "core/hle/kernel/process.h"
|
2019-09-21 19:46:53 -07:00
|
|
|
#include "core/hle/service/am/am.h"
|
2018-08-31 09:21:34 -07:00
|
|
|
#include "core/hle/service/filesystem/filesystem.h"
|
2018-10-23 16:28:17 -07:00
|
|
|
#include "core/hle/service/nfp/nfp.h"
|
|
|
|
#include "core/hle/service/sm/sm.h"
|
2015-09-10 21:23:00 -07:00
|
|
|
#include "core/loader/loader.h"
|
2018-08-31 09:21:34 -07:00
|
|
|
#include "core/perf_stats.h"
|
2016-09-17 17:38:01 -07:00
|
|
|
#include "core/settings.h"
|
2018-08-31 09:21:34 -07:00
|
|
|
#include "core/telemetry_session.h"
|
2020-07-09 20:36:38 -07:00
|
|
|
#include "video_core/gpu.h"
|
|
|
|
#include "video_core/shader_notify.h"
|
2018-01-14 10:15:45 -08:00
|
|
|
#include "yuzu/about_dialog.h"
|
2018-01-11 19:33:56 -08:00
|
|
|
#include "yuzu/bootmanager.h"
|
2018-09-16 11:05:51 -07:00
|
|
|
#include "yuzu/compatdb.h"
|
2018-09-09 16:09:37 -07:00
|
|
|
#include "yuzu/compatibility_list.h"
|
2018-01-11 19:33:56 -08:00
|
|
|
#include "yuzu/configuration/config.h"
|
|
|
|
#include "yuzu/configuration/configure_dialog.h"
|
2018-07-02 10:10:41 -07:00
|
|
|
#include "yuzu/debugger/console.h"
|
2018-01-11 19:33:56 -08:00
|
|
|
#include "yuzu/debugger/profiler.h"
|
|
|
|
#include "yuzu/debugger/wait_tree.h"
|
2018-09-16 11:05:51 -07:00
|
|
|
#include "yuzu/discord.h"
|
2018-01-11 19:33:56 -08:00
|
|
|
#include "yuzu/game_list.h"
|
2018-08-31 09:21:34 -07:00
|
|
|
#include "yuzu/game_list_p.h"
|
2018-01-11 19:33:56 -08:00
|
|
|
#include "yuzu/hotkeys.h"
|
2020-04-16 20:27:38 -07:00
|
|
|
#include "yuzu/install_dialog.h"
|
2019-01-16 23:01:00 -08:00
|
|
|
#include "yuzu/loading_screen.h"
|
2018-01-11 19:33:56 -08:00
|
|
|
#include "yuzu/main.h"
|
2019-07-29 13:06:33 -07:00
|
|
|
#include "yuzu/uisettings.h"
|
2015-05-18 21:21:33 -07:00
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
#ifdef USE_DISCORD_PRESENCE
|
|
|
|
#include "yuzu/discord_impl.h"
|
|
|
|
#endif
|
|
|
|
|
2018-12-24 13:23:31 -08:00
|
|
|
#ifdef YUZU_USE_QT_WEB_ENGINE
|
|
|
|
#include <QWebEngineProfile>
|
|
|
|
#include <QWebEngineScript>
|
|
|
|
#include <QWebEngineScriptCollection>
|
|
|
|
#include <QWebEngineSettings>
|
|
|
|
#include <QWebEngineView>
|
|
|
|
#endif
|
|
|
|
|
2016-08-01 14:13:35 -07:00
|
|
|
#ifdef QT_STATICPLUGIN
|
|
|
|
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
|
|
|
#endif
|
|
|
|
|
2018-04-19 11:22:26 -07:00
|
|
|
#ifdef _WIN32
|
2019-09-03 14:00:34 -07:00
|
|
|
#include <windows.h>
|
2018-04-19 11:22:26 -07:00
|
|
|
extern "C" {
|
|
|
|
// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
|
|
|
|
// graphics
|
|
|
|
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
|
|
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-04-10 19:22:50 -07:00
|
|
|
constexpr int default_mouse_timeout = 2500;
|
|
|
|
|
2018-10-17 15:27:23 -07:00
|
|
|
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
|
|
|
|
|
2017-08-08 17:06:25 -07:00
|
|
|
/**
|
|
|
|
* "Callouts" are one-time instructional messages shown to the user. In the config settings, there
|
|
|
|
* is a bitfield "callout_flags" options, used to track if a message has already been shown to the
|
|
|
|
* user. This is 32-bits - if we have more than 32 callouts, we should retire and recyle old ones.
|
|
|
|
*/
|
|
|
|
enum class CalloutFlag : uint32_t {
|
|
|
|
Telemetry = 0x1,
|
2018-09-04 11:44:40 -07:00
|
|
|
DRDDeprecation = 0x2,
|
2017-08-08 17:06:25 -07:00
|
|
|
};
|
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
void GMainWindow::ShowTelemetryCallout() {
|
|
|
|
if (UISettings::values.callout_flags & static_cast<uint32_t>(CalloutFlag::Telemetry)) {
|
2017-08-08 17:06:25 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
UISettings::values.callout_flags |= static_cast<uint32_t>(CalloutFlag::Telemetry);
|
2018-09-17 08:16:01 -07:00
|
|
|
const QString telemetry_message =
|
2018-10-06 00:15:27 -07:00
|
|
|
tr("<a href='https://yuzu-emu.org/help/feature/telemetry/'>Anonymous "
|
2018-09-16 11:05:51 -07:00
|
|
|
"data is collected</a> to help improve yuzu. "
|
|
|
|
"<br/><br/>Would you like to share your usage data with us?");
|
|
|
|
if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) {
|
|
|
|
Settings::values.enable_telemetry = false;
|
|
|
|
Settings::Apply();
|
|
|
|
}
|
2017-08-08 17:06:25 -07:00
|
|
|
}
|
|
|
|
|
2018-08-08 18:44:59 -07:00
|
|
|
const int GMainWindow::max_recent_files_item;
|
|
|
|
|
2018-08-23 16:52:06 -07:00
|
|
|
static void InitializeLogging() {
|
|
|
|
Log::Filter log_filter;
|
|
|
|
log_filter.ParseFilterString(Settings::values.log_filter);
|
|
|
|
Log::SetGlobalFilter(log_filter);
|
|
|
|
|
2020-08-15 05:33:16 -07:00
|
|
|
const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir);
|
|
|
|
Common::FS::CreateFullPath(log_dir);
|
2018-08-23 16:52:06 -07:00
|
|
|
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
|
2018-10-04 20:22:49 -07:00
|
|
|
#ifdef _WIN32
|
|
|
|
Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
|
|
|
|
#endif
|
2018-08-23 16:52:06 -07:00
|
|
|
}
|
|
|
|
|
2018-08-03 08:51:48 -07:00
|
|
|
GMainWindow::GMainWindow()
|
|
|
|
: config(new Config()), emu_thread(nullptr),
|
2019-03-04 09:40:53 -08:00
|
|
|
vfs(std::make_shared<FileSys::RealVfsFilesystem>()),
|
|
|
|
provider(std::make_unique<FileSys::ManualContentProvider>()) {
|
2018-08-23 16:52:06 -07:00
|
|
|
InitializeLogging();
|
2018-03-22 13:19:35 -07:00
|
|
|
|
2020-01-25 15:26:07 -08:00
|
|
|
LoadTranslation();
|
|
|
|
|
2017-02-15 19:23:30 -08:00
|
|
|
setAcceptDrops(true);
|
2014-03-31 19:26:50 -07:00
|
|
|
ui.setupUi(this);
|
|
|
|
statusBar()->hide();
|
|
|
|
|
2018-03-30 08:38:34 -07:00
|
|
|
default_theme_paths = QIcon::themeSearchPaths();
|
|
|
|
UpdateUITheme();
|
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
SetDiscordEnabled(UISettings::values.enable_discord_presence);
|
|
|
|
discord_rpc->Update();
|
|
|
|
|
2016-12-19 11:50:58 -08:00
|
|
|
InitializeWidgets();
|
2017-02-18 02:16:24 -08:00
|
|
|
InitializeDebugWidgets();
|
2016-12-19 11:50:58 -08:00
|
|
|
InitializeRecentFileMenuActions();
|
|
|
|
InitializeHotkeys();
|
|
|
|
|
|
|
|
SetDefaultUIGeometry();
|
|
|
|
RestoreUIState();
|
|
|
|
|
2017-02-18 02:26:57 -08:00
|
|
|
ConnectMenuEvents();
|
2016-12-19 11:50:58 -08:00
|
|
|
ConnectWidgetEvents();
|
2019-05-08 22:41:33 -07:00
|
|
|
|
2020-04-07 13:41:45 -07:00
|
|
|
const auto build_id = std::string(Common::g_build_id);
|
|
|
|
const auto fmt = std::string(Common::g_title_bar_format_idle);
|
2020-04-07 13:59:09 -07:00
|
|
|
const auto yuzu_build_version =
|
2020-04-07 13:41:45 -07:00
|
|
|
fmt::format(fmt.empty() ? "yuzu Development Build" : fmt, std::string{}, std::string{},
|
|
|
|
std::string{}, std::string{}, std::string{}, build_id);
|
|
|
|
|
2020-04-07 13:59:09 -07:00
|
|
|
LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", yuzu_build_version, Common::g_scm_branch,
|
2018-07-26 06:51:14 -07:00
|
|
|
Common::g_scm_desc);
|
2019-09-21 05:24:16 -07:00
|
|
|
#ifdef ARCHITECTURE_x86_64
|
2020-05-16 04:35:15 -07:00
|
|
|
const auto& caps = Common::GetCPUCaps();
|
|
|
|
std::string cpu_string = caps.cpu_string;
|
|
|
|
if (caps.avx || caps.avx2 || caps.avx512) {
|
|
|
|
cpu_string += " | AVX";
|
|
|
|
if (caps.avx512) {
|
|
|
|
cpu_string += "512";
|
|
|
|
} else if (caps.avx2) {
|
|
|
|
cpu_string += '2';
|
|
|
|
}
|
|
|
|
if (caps.fma || caps.fma4) {
|
|
|
|
cpu_string += " | FMA";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG_INFO(Frontend, "Host CPU: {}", cpu_string);
|
2019-09-21 05:24:16 -07:00
|
|
|
#endif
|
|
|
|
LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString());
|
2020-05-17 11:45:12 -07:00
|
|
|
LOG_INFO(Frontend, "Host RAM: {:.2f} GB",
|
|
|
|
Common::GetMemInfo().TotalPhysicalMemory / 1024.0f / 1024 / 1024);
|
2020-05-27 08:21:59 -07:00
|
|
|
LOG_INFO(Frontend, "Host Swap: {:.2f} GB",
|
2020-05-17 11:45:12 -07:00
|
|
|
Common::GetMemInfo().TotalSwapMemory / 1024.0f / 1024 / 1024);
|
2019-05-08 22:41:33 -07:00
|
|
|
UpdateWindowTitle();
|
2016-12-19 11:50:58 -08:00
|
|
|
|
|
|
|
show();
|
|
|
|
|
2019-03-04 09:40:53 -08:00
|
|
|
Core::System::GetInstance().SetContentProvider(
|
|
|
|
std::make_unique<FileSys::ContentProviderUnion>());
|
|
|
|
Core::System::GetInstance().RegisterContentProvider(
|
|
|
|
FileSys::ContentProviderUnionSlot::FrontendManual, provider.get());
|
2019-04-22 14:56:56 -07:00
|
|
|
Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
|
2019-03-04 09:40:53 -08:00
|
|
|
|
2018-09-23 18:06:33 -07:00
|
|
|
// Gen keys if necessary
|
2018-09-29 08:48:51 -07:00
|
|
|
OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning);
|
2018-09-23 18:06:33 -07:00
|
|
|
|
2018-08-29 06:42:53 -07:00
|
|
|
game_list->LoadCompatibilityList();
|
2019-05-01 14:21:04 -07:00
|
|
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
2016-12-19 11:50:58 -08:00
|
|
|
|
2017-08-08 17:06:25 -07:00
|
|
|
// Show one-time "callout" messages to the user
|
2018-09-16 11:05:51 -07:00
|
|
|
ShowTelemetryCallout();
|
2017-08-08 17:06:25 -07:00
|
|
|
|
2020-04-10 19:22:50 -07:00
|
|
|
// make sure menubar has the arrow cursor instead of inheriting from this
|
|
|
|
ui.menubar->setCursor(QCursor());
|
|
|
|
statusBar()->setCursor(QCursor());
|
|
|
|
|
|
|
|
mouse_hide_timer.setInterval(default_mouse_timeout);
|
|
|
|
connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor);
|
|
|
|
connect(ui.menubar, &QMenuBar::hovered, this, &GMainWindow::ShowMouseCursor);
|
|
|
|
|
2016-12-19 11:50:58 -08:00
|
|
|
QStringList args = QApplication::arguments();
|
|
|
|
if (args.length() >= 2) {
|
2017-02-16 22:32:22 -08:00
|
|
|
BootGame(args[1]);
|
2016-12-19 11:50:58 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GMainWindow::~GMainWindow() {
|
|
|
|
// will get automatically deleted otherwise
|
|
|
|
if (render_window->parent() == nullptr)
|
|
|
|
delete render_window;
|
|
|
|
}
|
|
|
|
|
2018-11-22 18:03:33 -08:00
|
|
|
void GMainWindow::ProfileSelectorSelectProfile() {
|
2020-07-11 07:08:34 -07:00
|
|
|
const Service::Account::ProfileManager manager;
|
|
|
|
int index = 0;
|
|
|
|
if (manager.GetUserCount() != 1) {
|
|
|
|
QtProfileSelectionDialog dialog(this);
|
|
|
|
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
|
|
|
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
|
|
|
dialog.setWindowModality(Qt::WindowModal);
|
|
|
|
if (dialog.exec() == QDialog::Rejected) {
|
|
|
|
emit ProfileSelectorFinishedSelection(std::nullopt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
index = dialog.GetIndex();
|
2018-11-22 18:03:33 -08:00
|
|
|
}
|
|
|
|
|
2020-07-11 07:08:34 -07:00
|
|
|
const auto uuid = manager.GetUser(static_cast<std::size_t>(index));
|
2018-11-22 18:03:33 -08:00
|
|
|
if (!uuid.has_value()) {
|
|
|
|
emit ProfileSelectorFinishedSelection(std::nullopt);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit ProfileSelectorFinishedSelection(uuid);
|
|
|
|
}
|
|
|
|
|
2018-11-12 08:08:09 -08:00
|
|
|
void GMainWindow::SoftwareKeyboardGetText(
|
2018-11-11 17:16:38 -08:00
|
|
|
const Core::Frontend::SoftwareKeyboardParameters& parameters) {
|
2018-11-11 13:41:31 -08:00
|
|
|
QtSoftwareKeyboardDialog dialog(this, parameters);
|
|
|
|
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
|
|
|
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
|
|
|
dialog.setWindowModality(Qt::WindowModal);
|
|
|
|
|
2019-05-28 21:52:47 -07:00
|
|
|
if (dialog.exec() == QDialog::Rejected) {
|
2018-11-12 08:08:09 -08:00
|
|
|
emit SoftwareKeyboardFinishedText(std::nullopt);
|
2018-11-17 09:18:03 -08:00
|
|
|
return;
|
|
|
|
}
|
2018-11-11 17:16:38 -08:00
|
|
|
|
2018-11-12 08:08:09 -08:00
|
|
|
emit SoftwareKeyboardFinishedText(dialog.GetText());
|
2018-11-11 13:41:31 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) {
|
|
|
|
QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message));
|
2018-11-17 09:18:03 -08:00
|
|
|
emit SoftwareKeyboardFinishedCheckDialog();
|
2018-11-11 13:41:31 -08:00
|
|
|
}
|
|
|
|
|
2018-12-24 13:23:31 -08:00
|
|
|
#ifdef YUZU_USE_QT_WEB_ENGINE
|
|
|
|
|
|
|
|
void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
|
|
|
|
NXInputWebEngineView web_browser_view(this);
|
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
// Scope to contain the QProgressDialog for initialization
|
2018-12-24 13:23:31 -08:00
|
|
|
{
|
|
|
|
QProgressDialog progress(this);
|
|
|
|
progress.setMinimumDuration(200);
|
|
|
|
progress.setLabelText(tr("Loading Web Applet..."));
|
|
|
|
progress.setRange(0, 4);
|
|
|
|
progress.setValue(0);
|
|
|
|
progress.show();
|
|
|
|
|
|
|
|
auto future = QtConcurrent::run([this] { emit WebBrowserUnpackRomFS(); });
|
|
|
|
|
|
|
|
while (!future.isFinished())
|
|
|
|
QApplication::processEvents();
|
|
|
|
|
|
|
|
progress.setValue(1);
|
|
|
|
|
|
|
|
// Load the special shim script to handle input and exit.
|
|
|
|
QWebEngineScript nx_shim;
|
|
|
|
nx_shim.setSourceCode(GetNXShimInjectionScript());
|
|
|
|
nx_shim.setWorldId(QWebEngineScript::MainWorld);
|
2019-05-24 16:44:06 -07:00
|
|
|
nx_shim.setName(QStringLiteral("nx_inject.js"));
|
2018-12-24 13:23:31 -08:00
|
|
|
nx_shim.setInjectionPoint(QWebEngineScript::DocumentCreation);
|
|
|
|
nx_shim.setRunsOnSubFrames(true);
|
|
|
|
web_browser_view.page()->profile()->scripts()->insert(nx_shim);
|
|
|
|
|
|
|
|
web_browser_view.load(
|
|
|
|
QUrl(QUrl::fromLocalFile(QString::fromStdString(std::string(filename))).toString() +
|
|
|
|
QString::fromStdString(std::string(additional_args))));
|
|
|
|
|
|
|
|
progress.setValue(2);
|
|
|
|
|
|
|
|
render_window->hide();
|
|
|
|
web_browser_view.setFocus();
|
|
|
|
|
|
|
|
const auto& layout = render_window->GetFramebufferLayout();
|
|
|
|
web_browser_view.resize(layout.screen.GetWidth(), layout.screen.GetHeight());
|
|
|
|
web_browser_view.move(layout.screen.left, layout.screen.top + menuBar()->height());
|
|
|
|
web_browser_view.setZoomFactor(static_cast<qreal>(layout.screen.GetWidth()) /
|
|
|
|
Layout::ScreenUndocked::Width);
|
|
|
|
web_browser_view.settings()->setAttribute(
|
|
|
|
QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
|
|
|
|
|
|
|
|
web_browser_view.show();
|
|
|
|
|
|
|
|
progress.setValue(3);
|
|
|
|
|
|
|
|
QApplication::processEvents();
|
|
|
|
|
|
|
|
progress.setValue(4);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool finished = false;
|
|
|
|
QAction* exit_action = new QAction(tr("Exit Web Applet"), this);
|
|
|
|
connect(exit_action, &QAction::triggered, this, [&finished] { finished = true; });
|
|
|
|
ui.menubar->addAction(exit_action);
|
|
|
|
|
|
|
|
auto& npad =
|
|
|
|
Core::System::GetInstance()
|
|
|
|
.ServiceManager()
|
|
|
|
.GetService<Service::HID::Hid>("hid")
|
|
|
|
->GetAppletResource()
|
|
|
|
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
|
|
|
|
|
|
|
|
const auto fire_js_keypress = [&web_browser_view](u32 key_code) {
|
|
|
|
web_browser_view.page()->runJavaScript(
|
|
|
|
QStringLiteral("document.dispatchEvent(new KeyboardEvent('keydown', {'key': %1}));")
|
2019-05-24 16:44:06 -07:00
|
|
|
.arg(key_code));
|
2018-12-24 13:23:31 -08:00
|
|
|
};
|
|
|
|
|
2019-03-04 15:24:16 -08:00
|
|
|
QMessageBox::information(
|
|
|
|
this, tr("Exit"),
|
|
|
|
tr("To exit the web application, use the game provided controls to select exit, select the "
|
|
|
|
"'Exit Web Applet' option in the menu bar, or press the 'Enter' key."));
|
|
|
|
|
2018-12-24 13:23:31 -08:00
|
|
|
bool running_exit_check = false;
|
|
|
|
while (!finished) {
|
|
|
|
QApplication::processEvents();
|
|
|
|
|
|
|
|
if (!running_exit_check) {
|
|
|
|
web_browser_view.page()->runJavaScript(QStringLiteral("applet_done;"),
|
|
|
|
[&](const QVariant& res) {
|
|
|
|
running_exit_check = false;
|
|
|
|
if (res.toBool())
|
|
|
|
finished = true;
|
|
|
|
});
|
|
|
|
running_exit_check = true;
|
|
|
|
}
|
|
|
|
|
2018-12-28 16:29:44 -08:00
|
|
|
const auto input = npad.GetAndResetPressState();
|
2018-12-24 13:23:31 -08:00
|
|
|
for (std::size_t i = 0; i < Settings::NativeButton::NumButtons; ++i) {
|
|
|
|
if ((input & (1 << i)) != 0) {
|
|
|
|
LOG_DEBUG(Frontend, "firing input for button id={:02X}", i);
|
|
|
|
web_browser_view.page()->runJavaScript(
|
|
|
|
QStringLiteral("yuzu_key_callbacks[%1]();").arg(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (input & 0x00888000) // RStick Down | LStick Down | DPad Down
|
|
|
|
fire_js_keypress(40); // Down Arrow Key
|
|
|
|
else if (input & 0x00444000) // RStick Right | LStick Right | DPad Right
|
|
|
|
fire_js_keypress(39); // Right Arrow Key
|
|
|
|
else if (input & 0x00222000) // RStick Up | LStick Up | DPad Up
|
|
|
|
fire_js_keypress(38); // Up Arrow Key
|
|
|
|
else if (input & 0x00111000) // RStick Left | LStick Left | DPad Left
|
|
|
|
fire_js_keypress(37); // Left Arrow Key
|
|
|
|
else if (input & 0x00000001) // A Button
|
|
|
|
fire_js_keypress(13); // Enter Key
|
|
|
|
}
|
|
|
|
|
|
|
|
web_browser_view.hide();
|
|
|
|
render_window->show();
|
|
|
|
render_window->setFocus();
|
|
|
|
ui.menubar->removeAction(exit_action);
|
|
|
|
|
|
|
|
// Needed to update render window focus/show and remove menubar action
|
|
|
|
QApplication::processEvents();
|
|
|
|
emit WebBrowserFinishedBrowsing();
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
void GMainWindow::WebBrowserOpenPage(std::string_view filename, std::string_view additional_args) {
|
|
|
|
QMessageBox::warning(
|
|
|
|
this, tr("Web Applet"),
|
|
|
|
tr("This version of yuzu was built without QtWebEngine support, meaning that yuzu cannot "
|
|
|
|
"properly display the game manual or web page requested."),
|
|
|
|
QMessageBox::Ok, QMessageBox::Ok);
|
|
|
|
|
|
|
|
LOG_INFO(Frontend,
|
|
|
|
"(STUBBED) called - Missing QtWebEngine dependency needed to open website page at "
|
|
|
|
"'{}' with arguments '{}'!",
|
|
|
|
filename, additional_args);
|
|
|
|
|
|
|
|
emit WebBrowserFinishedBrowsing();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2016-12-19 11:50:58 -08:00
|
|
|
void GMainWindow::InitializeWidgets() {
|
2018-09-16 11:05:51 -07:00
|
|
|
#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING
|
|
|
|
ui.action_Report_Compatibility->setVisible(true);
|
|
|
|
#endif
|
2015-04-28 21:01:41 -07:00
|
|
|
render_window = new GRenderWindow(this, emu_thread.get());
|
2014-04-21 20:15:17 -07:00
|
|
|
render_window->hide();
|
2014-03-31 19:26:50 -07:00
|
|
|
|
2019-03-04 09:40:53 -08:00
|
|
|
game_list = new GameList(vfs, provider.get(), this);
|
2015-08-31 21:35:33 -07:00
|
|
|
ui.horizontalLayout->addWidget(game_list);
|
2017-02-18 12:09:14 -08:00
|
|
|
|
2019-05-01 14:21:04 -07:00
|
|
|
game_list_placeholder = new GameListPlaceholder(this);
|
|
|
|
ui.horizontalLayout->addWidget(game_list_placeholder);
|
|
|
|
game_list_placeholder->setVisible(false);
|
|
|
|
|
2019-01-16 23:01:00 -08:00
|
|
|
loading_screen = new LoadingScreen(this);
|
|
|
|
loading_screen->hide();
|
|
|
|
ui.horizontalLayout->addWidget(loading_screen);
|
2019-01-21 08:20:16 -08:00
|
|
|
connect(loading_screen, &LoadingScreen::Hidden, [&] {
|
|
|
|
loading_screen->Clear();
|
|
|
|
if (emulation_running) {
|
|
|
|
render_window->show();
|
|
|
|
render_window->setFocus();
|
|
|
|
}
|
|
|
|
});
|
2019-01-16 23:01:00 -08:00
|
|
|
|
2017-02-18 12:09:14 -08:00
|
|
|
// Create status bar
|
2017-04-12 22:10:19 -07:00
|
|
|
message_label = new QLabel();
|
|
|
|
// Configured separately for left alignment
|
|
|
|
message_label->setFrameStyle(QFrame::NoFrame);
|
|
|
|
message_label->setContentsMargins(4, 0, 4, 0);
|
|
|
|
message_label->setAlignment(Qt::AlignLeft);
|
|
|
|
statusBar()->addPermanentWidget(message_label, 1);
|
|
|
|
|
2020-07-09 20:36:38 -07:00
|
|
|
shader_building_label = new QLabel();
|
|
|
|
shader_building_label->setToolTip(tr("The amount of shaders currently being built"));
|
2017-02-18 12:09:14 -08:00
|
|
|
emu_speed_label = new QLabel();
|
2018-01-16 10:05:21 -08:00
|
|
|
emu_speed_label->setToolTip(
|
|
|
|
tr("Current emulation speed. Values higher or lower than 100% "
|
|
|
|
"indicate emulation is running faster or slower than a Switch."));
|
2017-02-18 12:09:14 -08:00
|
|
|
game_fps_label = new QLabel();
|
2017-02-19 19:09:46 -08:00
|
|
|
game_fps_label->setToolTip(tr("How many frames per second the game is currently displaying. "
|
|
|
|
"This will vary from game to game and scene to scene."));
|
2017-02-18 12:09:14 -08:00
|
|
|
emu_frametime_label = new QLabel();
|
2017-02-19 19:09:46 -08:00
|
|
|
emu_frametime_label->setToolTip(
|
2018-01-13 15:49:16 -08:00
|
|
|
tr("Time taken to emulate a Switch frame, not counting framelimiting or v-sync. For "
|
2017-02-19 19:09:46 -08:00
|
|
|
"full-speed emulation this should be at most 16.67 ms."));
|
2017-02-18 12:09:14 -08:00
|
|
|
|
2020-07-09 20:36:38 -07:00
|
|
|
for (auto& label :
|
|
|
|
{shader_building_label, emu_speed_label, game_fps_label, emu_frametime_label}) {
|
2017-02-18 12:09:14 -08:00
|
|
|
label->setVisible(false);
|
2017-02-20 16:53:40 -08:00
|
|
|
label->setFrameStyle(QFrame::NoFrame);
|
|
|
|
label->setContentsMargins(4, 0, 4, 0);
|
2020-01-28 14:59:30 -08:00
|
|
|
statusBar()->addPermanentWidget(label);
|
2017-02-18 12:09:14 -08:00
|
|
|
}
|
2020-01-28 14:59:30 -08:00
|
|
|
|
|
|
|
// Setup Dock button
|
|
|
|
dock_status_button = new QPushButton();
|
|
|
|
dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
|
|
|
|
dock_status_button->setFocusPolicy(Qt::NoFocus);
|
|
|
|
connect(dock_status_button, &QPushButton::clicked, [&] {
|
|
|
|
Settings::values.use_docked_mode = !Settings::values.use_docked_mode;
|
|
|
|
dock_status_button->setChecked(Settings::values.use_docked_mode);
|
|
|
|
OnDockedModeChanged(!Settings::values.use_docked_mode, Settings::values.use_docked_mode);
|
|
|
|
});
|
|
|
|
dock_status_button->setText(tr("DOCK"));
|
|
|
|
dock_status_button->setCheckable(true);
|
|
|
|
dock_status_button->setChecked(Settings::values.use_docked_mode);
|
|
|
|
statusBar()->insertPermanentWidget(0, dock_status_button);
|
|
|
|
|
|
|
|
// Setup ASync button
|
|
|
|
async_status_button = new QPushButton();
|
|
|
|
async_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
|
|
|
|
async_status_button->setFocusPolicy(Qt::NoFocus);
|
|
|
|
connect(async_status_button, &QPushButton::clicked, [&] {
|
|
|
|
if (emulation_running) {
|
|
|
|
return;
|
|
|
|
}
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
bool is_async = !Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
|
|
|
|
Settings::values.use_multi_core.GetValue();
|
|
|
|
Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);
|
|
|
|
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
|
2020-01-28 14:59:30 -08:00
|
|
|
Settings::Apply();
|
|
|
|
});
|
|
|
|
async_status_button->setText(tr("ASYNC"));
|
|
|
|
async_status_button->setCheckable(true);
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
|
2020-03-15 18:34:22 -07:00
|
|
|
|
|
|
|
// Setup Multicore button
|
|
|
|
multicore_status_button = new QPushButton();
|
|
|
|
multicore_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
|
|
|
|
multicore_status_button->setFocusPolicy(Qt::NoFocus);
|
|
|
|
connect(multicore_status_button, &QPushButton::clicked, [&] {
|
|
|
|
if (emulation_running) {
|
|
|
|
return;
|
|
|
|
}
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue());
|
|
|
|
bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
|
|
|
|
Settings::values.use_multi_core.GetValue();
|
|
|
|
Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async);
|
|
|
|
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
|
|
|
|
multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
|
2020-03-15 18:34:22 -07:00
|
|
|
Settings::Apply();
|
|
|
|
});
|
|
|
|
multicore_status_button->setText(tr("MULTICORE"));
|
|
|
|
multicore_status_button->setCheckable(true);
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
|
2020-03-15 18:34:22 -07:00
|
|
|
statusBar()->insertPermanentWidget(0, multicore_status_button);
|
2020-01-28 14:59:30 -08:00
|
|
|
statusBar()->insertPermanentWidget(0, async_status_button);
|
|
|
|
|
|
|
|
// Setup Renderer API button
|
|
|
|
renderer_status_button = new QPushButton();
|
|
|
|
renderer_status_button->setObjectName(QStringLiteral("RendererStatusBarButton"));
|
|
|
|
renderer_status_button->setCheckable(true);
|
|
|
|
renderer_status_button->setFocusPolicy(Qt::NoFocus);
|
2020-08-03 08:28:18 -07:00
|
|
|
connect(renderer_status_button, &QPushButton::toggled, [this](bool checked) {
|
2020-01-28 14:59:30 -08:00
|
|
|
renderer_status_button->setText(checked ? tr("VULKAN") : tr("OPENGL"));
|
|
|
|
});
|
|
|
|
renderer_status_button->toggle();
|
|
|
|
|
|
|
|
#ifndef HAS_VULKAN
|
|
|
|
renderer_status_button->setChecked(false);
|
|
|
|
renderer_status_button->setCheckable(false);
|
|
|
|
renderer_status_button->setDisabled(true);
|
|
|
|
#else
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
|
2020-01-28 14:59:30 -08:00
|
|
|
Settings::RendererBackend::Vulkan);
|
2020-08-03 08:28:18 -07:00
|
|
|
connect(renderer_status_button, &QPushButton::clicked, [this] {
|
2020-01-28 14:59:30 -08:00
|
|
|
if (emulation_running) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (renderer_status_button->isChecked()) {
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan);
|
2020-01-28 14:59:30 -08:00
|
|
|
} else {
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL);
|
2020-01-28 14:59:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Settings::Apply();
|
|
|
|
});
|
|
|
|
#endif // HAS_VULKAN
|
|
|
|
statusBar()->insertPermanentWidget(0, renderer_status_button);
|
|
|
|
|
2017-02-18 12:09:14 -08:00
|
|
|
statusBar()->setVisible(true);
|
2019-05-24 16:44:06 -07:00
|
|
|
setStyleSheet(QStringLiteral("QStatusBar::item{border: none;}"));
|
2017-02-18 02:16:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::InitializeDebugWidgets() {
|
|
|
|
QMenu* debug_menu = ui.menu_View_Debugging;
|
2015-08-31 21:35:33 -07:00
|
|
|
|
2016-04-28 17:17:31 -07:00
|
|
|
#if MICROPROFILE_ENABLED
|
2015-08-17 14:25:21 -07:00
|
|
|
microProfileDialog = new MicroProfileDialog(this);
|
|
|
|
microProfileDialog->hide();
|
2017-02-18 02:16:24 -08:00
|
|
|
debug_menu->addAction(microProfileDialog->toggleViewAction());
|
2016-04-28 17:17:31 -07:00
|
|
|
#endif
|
2015-08-17 14:25:21 -07:00
|
|
|
|
2016-04-08 09:28:54 -07:00
|
|
|
waitTreeWidget = new WaitTreeWidget(this);
|
|
|
|
addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
|
|
|
|
waitTreeWidget->hide();
|
|
|
|
debug_menu->addAction(waitTreeWidget->toggleViewAction());
|
2017-02-18 02:16:24 -08:00
|
|
|
connect(this, &GMainWindow::EmulationStarting, waitTreeWidget,
|
|
|
|
&WaitTreeWidget::OnEmulationStarting);
|
|
|
|
connect(this, &GMainWindow::EmulationStopping, waitTreeWidget,
|
|
|
|
&WaitTreeWidget::OnEmulationStopping);
|
2016-12-19 11:50:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::InitializeRecentFileMenuActions() {
|
|
|
|
for (int i = 0; i < max_recent_files_item; ++i) {
|
|
|
|
actions_recent_files[i] = new QAction(this);
|
|
|
|
actions_recent_files[i]->setVisible(false);
|
2018-01-18 17:03:13 -08:00
|
|
|
connect(actions_recent_files[i], &QAction::triggered, this, &GMainWindow::OnMenuRecentFile);
|
2016-12-19 11:50:58 -08:00
|
|
|
|
|
|
|
ui.menu_recent_files->addAction(actions_recent_files[i]);
|
|
|
|
}
|
2018-08-21 04:12:45 -07:00
|
|
|
ui.menu_recent_files->addSeparator();
|
|
|
|
QAction* action_clear_recent_files = new QAction(this);
|
|
|
|
action_clear_recent_files->setText(tr("Clear Recent Files"));
|
|
|
|
connect(action_clear_recent_files, &QAction::triggered, this, [this] {
|
|
|
|
UISettings::values.recent_files.clear();
|
|
|
|
UpdateRecentFiles();
|
|
|
|
});
|
|
|
|
ui.menu_recent_files->addAction(action_clear_recent_files);
|
2016-12-19 11:50:58 -08:00
|
|
|
|
|
|
|
UpdateRecentFiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::InitializeHotkeys() {
|
2018-08-06 21:43:07 -07:00
|
|
|
hotkey_registry.LoadHotkeys();
|
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString main_window = QStringLiteral("Main Window");
|
|
|
|
const QString load_file = QStringLiteral("Load File");
|
2020-01-12 15:49:44 -08:00
|
|
|
const QString load_amiibo = QStringLiteral("Load Amiibo");
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString exit_yuzu = QStringLiteral("Exit yuzu");
|
2020-01-12 15:49:44 -08:00
|
|
|
const QString restart_emulation = QStringLiteral("Restart Emulation");
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString stop_emulation = QStringLiteral("Stop Emulation");
|
|
|
|
const QString toggle_filter_bar = QStringLiteral("Toggle Filter Bar");
|
|
|
|
const QString toggle_status_bar = QStringLiteral("Toggle Status Bar");
|
|
|
|
const QString fullscreen = QStringLiteral("Fullscreen");
|
2020-01-12 15:49:44 -08:00
|
|
|
const QString capture_screenshot = QStringLiteral("Capture Screenshot");
|
2019-05-24 16:44:06 -07:00
|
|
|
|
|
|
|
ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence(main_window, load_file));
|
2019-02-16 07:19:29 -08:00
|
|
|
ui.action_Load_File->setShortcutContext(
|
2019-05-24 16:44:06 -07:00
|
|
|
hotkey_registry.GetShortcutContext(main_window, load_file));
|
2019-02-16 07:19:29 -08:00
|
|
|
|
2020-01-12 15:49:44 -08:00
|
|
|
ui.action_Load_Amiibo->setShortcut(hotkey_registry.GetKeySequence(main_window, load_amiibo));
|
|
|
|
ui.action_Load_Amiibo->setShortcutContext(
|
|
|
|
hotkey_registry.GetShortcutContext(main_window, load_amiibo));
|
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence(main_window, exit_yuzu));
|
|
|
|
ui.action_Exit->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, exit_yuzu));
|
2019-02-16 07:19:29 -08:00
|
|
|
|
2020-01-12 15:49:44 -08:00
|
|
|
ui.action_Restart->setShortcut(hotkey_registry.GetKeySequence(main_window, restart_emulation));
|
|
|
|
ui.action_Restart->setShortcutContext(
|
|
|
|
hotkey_registry.GetShortcutContext(main_window, restart_emulation));
|
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence(main_window, stop_emulation));
|
2019-02-16 07:19:29 -08:00
|
|
|
ui.action_Stop->setShortcutContext(
|
2019-05-24 16:44:06 -07:00
|
|
|
hotkey_registry.GetShortcutContext(main_window, stop_emulation));
|
2019-02-16 07:19:29 -08:00
|
|
|
|
|
|
|
ui.action_Show_Filter_Bar->setShortcut(
|
2019-05-24 16:44:06 -07:00
|
|
|
hotkey_registry.GetKeySequence(main_window, toggle_filter_bar));
|
2019-02-16 07:19:29 -08:00
|
|
|
ui.action_Show_Filter_Bar->setShortcutContext(
|
2019-05-24 16:44:06 -07:00
|
|
|
hotkey_registry.GetShortcutContext(main_window, toggle_filter_bar));
|
2019-02-16 07:19:29 -08:00
|
|
|
|
|
|
|
ui.action_Show_Status_Bar->setShortcut(
|
2019-05-24 16:44:06 -07:00
|
|
|
hotkey_registry.GetKeySequence(main_window, toggle_status_bar));
|
2019-02-16 07:19:29 -08:00
|
|
|
ui.action_Show_Status_Bar->setShortcutContext(
|
2019-05-24 16:44:06 -07:00
|
|
|
hotkey_registry.GetShortcutContext(main_window, toggle_status_bar));
|
|
|
|
|
2020-01-12 15:49:44 -08:00
|
|
|
ui.action_Capture_Screenshot->setShortcut(
|
|
|
|
hotkey_registry.GetKeySequence(main_window, capture_screenshot));
|
|
|
|
ui.action_Capture_Screenshot->setShortcutContext(
|
|
|
|
hotkey_registry.GetShortcutContext(main_window, capture_screenshot));
|
|
|
|
|
2020-06-25 13:54:05 -07:00
|
|
|
ui.action_Fullscreen->setShortcut(
|
|
|
|
hotkey_registry.GetHotkey(main_window, fullscreen, this)->key());
|
|
|
|
ui.action_Fullscreen->setShortcutContext(
|
|
|
|
hotkey_registry.GetShortcutContext(main_window, fullscreen));
|
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this),
|
|
|
|
&QShortcut::activated, this, &GMainWindow::OnMenuLoadFile);
|
|
|
|
connect(
|
|
|
|
hotkey_registry.GetHotkey(main_window, QStringLiteral("Continue/Pause Emulation"), this),
|
|
|
|
&QShortcut::activated, this, [&] {
|
|
|
|
if (emulation_running) {
|
|
|
|
if (emu_thread->IsRunning()) {
|
|
|
|
OnPauseGame();
|
|
|
|
} else {
|
|
|
|
OnStartGame();
|
2018-08-06 21:43:07 -07:00
|
|
|
}
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
|
|
|
});
|
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Restart Emulation"), this),
|
2019-02-16 07:19:29 -08:00
|
|
|
&QShortcut::activated, this, [this] {
|
2019-05-24 16:44:06 -07:00
|
|
|
if (!Core::System::GetInstance().IsPoweredOn()) {
|
2018-08-21 04:24:55 -07:00
|
|
|
return;
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
|
|
|
BootGame(game_path);
|
2018-08-21 04:24:55 -07:00
|
|
|
});
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
|
2018-08-06 21:43:07 -07:00
|
|
|
&QShortcut::activated, ui.action_Fullscreen, &QAction::trigger);
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, fullscreen, render_window),
|
2018-08-06 21:43:07 -07:00
|
|
|
&QShortcut::activatedAmbiguously, ui.action_Fullscreen, &QAction::trigger);
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Exit Fullscreen"), this),
|
2018-08-06 21:43:07 -07:00
|
|
|
&QShortcut::activated, this, [&] {
|
|
|
|
if (emulation_running) {
|
|
|
|
ui.action_Fullscreen->setChecked(false);
|
|
|
|
ToggleFullscreen();
|
|
|
|
}
|
|
|
|
});
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
|
2018-08-06 21:43:07 -07:00
|
|
|
&QShortcut::activated, this, [&] {
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
Settings::values.use_frame_limit.SetValue(
|
|
|
|
!Settings::values.use_frame_limit.GetValue());
|
2018-08-06 21:43:07 -07:00
|
|
|
UpdateStatusBar();
|
|
|
|
});
|
2020-06-06 12:56:14 -07:00
|
|
|
constexpr u16 SPEED_LIMIT_STEP = 5;
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
|
2018-08-20 16:14:06 -07:00
|
|
|
&QShortcut::activated, this, [&] {
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
if (Settings::values.frame_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
|
|
|
|
Settings::values.frame_limit.SetValue(SPEED_LIMIT_STEP +
|
|
|
|
Settings::values.frame_limit.GetValue());
|
2018-08-20 16:14:06 -07:00
|
|
|
UpdateStatusBar();
|
|
|
|
}
|
|
|
|
});
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
|
2018-08-20 16:14:06 -07:00
|
|
|
&QShortcut::activated, this, [&] {
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) {
|
|
|
|
Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() -
|
|
|
|
SPEED_LIMIT_STEP);
|
2018-08-20 16:14:06 -07:00
|
|
|
UpdateStatusBar();
|
|
|
|
}
|
|
|
|
});
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load Amiibo"), this),
|
|
|
|
&QShortcut::activated, this, [&] {
|
2018-11-13 06:06:41 -08:00
|
|
|
if (ui.action_Load_Amiibo->isEnabled()) {
|
|
|
|
OnLoadAmiibo();
|
|
|
|
}
|
|
|
|
});
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Capture Screenshot"), this),
|
2018-08-30 23:16:16 -07:00
|
|
|
&QShortcut::activated, this, [&] {
|
2020-07-06 14:30:28 -07:00
|
|
|
if (emu_thread != nullptr && emu_thread->IsRunning()) {
|
2018-08-30 23:16:16 -07:00
|
|
|
OnCaptureScreenshot();
|
|
|
|
}
|
|
|
|
});
|
2019-05-24 16:44:06 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Change Docked Mode"), this),
|
2019-03-06 10:31:23 -08:00
|
|
|
&QShortcut::activated, this, [&] {
|
|
|
|
Settings::values.use_docked_mode = !Settings::values.use_docked_mode;
|
|
|
|
OnDockedModeChanged(!Settings::values.use_docked_mode,
|
|
|
|
Settings::values.use_docked_mode);
|
2020-01-28 14:59:30 -08:00
|
|
|
dock_status_button->setChecked(Settings::values.use_docked_mode);
|
2019-03-06 10:31:23 -08:00
|
|
|
});
|
2020-06-25 12:05:03 -07:00
|
|
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
|
|
|
|
&QShortcut::activated, this,
|
|
|
|
[] { Settings::values.audio_muted = !Settings::values.audio_muted; });
|
2016-12-19 11:50:58 -08:00
|
|
|
}
|
2014-03-31 19:26:50 -07:00
|
|
|
|
2016-12-19 11:50:58 -08:00
|
|
|
void GMainWindow::SetDefaultUIGeometry() {
|
2020-05-15 13:22:27 -07:00
|
|
|
// geometry: 53% of the window contents are in the upper screen half, 47% in the lower half
|
2016-12-19 11:50:58 -08:00
|
|
|
const QRect screenRect = QApplication::desktop()->screenGeometry(this);
|
|
|
|
|
|
|
|
const int w = screenRect.width() * 2 / 3;
|
2020-05-15 13:22:27 -07:00
|
|
|
const int h = screenRect.height() * 2 / 3;
|
2016-12-19 11:50:58 -08:00
|
|
|
const int x = (screenRect.x() + screenRect.width()) / 2 - w / 2;
|
2020-05-15 13:22:27 -07:00
|
|
|
const int y = (screenRect.y() + screenRect.height()) / 2 - h * 53 / 100;
|
2016-12-19 11:50:58 -08:00
|
|
|
|
2014-03-31 19:26:50 -07:00
|
|
|
setGeometry(x, y, w, h);
|
2016-12-19 11:50:58 -08:00
|
|
|
}
|
2014-03-31 19:26:50 -07:00
|
|
|
|
2016-12-19 11:50:58 -08:00
|
|
|
void GMainWindow::RestoreUIState() {
|
2016-01-24 12:23:55 -08:00
|
|
|
restoreGeometry(UISettings::values.geometry);
|
|
|
|
restoreState(UISettings::values.state);
|
|
|
|
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
2016-04-28 17:17:31 -07:00
|
|
|
#if MICROPROFILE_ENABLED
|
2016-01-24 12:23:55 -08:00
|
|
|
microProfileDialog->restoreGeometry(UISettings::values.microprofile_geometry);
|
|
|
|
microProfileDialog->setVisible(UISettings::values.microprofile_visible);
|
2016-04-28 17:17:31 -07:00
|
|
|
#endif
|
2015-09-06 23:51:57 -07:00
|
|
|
|
2016-01-24 12:23:55 -08:00
|
|
|
game_list->LoadInterfaceLayout();
|
2015-09-02 05:56:38 -07:00
|
|
|
|
2016-01-24 12:23:55 -08:00
|
|
|
ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
|
2014-04-21 20:15:17 -07:00
|
|
|
ToggleWindowMode();
|
2014-03-31 19:26:50 -07:00
|
|
|
|
2018-01-16 06:50:33 -08:00
|
|
|
ui.action_Fullscreen->setChecked(UISettings::values.fullscreen);
|
|
|
|
|
2017-02-18 01:11:57 -08:00
|
|
|
ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
|
|
|
|
OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
|
2017-02-18 12:09:14 -08:00
|
|
|
|
2017-04-29 19:04:39 -07:00
|
|
|
ui.action_Show_Filter_Bar->setChecked(UISettings::values.show_filter_bar);
|
|
|
|
game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked());
|
|
|
|
|
2017-02-18 12:09:14 -08:00
|
|
|
ui.action_Show_Status_Bar->setChecked(UISettings::values.show_status_bar);
|
|
|
|
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
|
2018-07-02 10:10:41 -07:00
|
|
|
Debugger::ToggleConsole();
|
2016-12-19 11:50:58 -08:00
|
|
|
}
|
2015-01-06 07:09:30 -08:00
|
|
|
|
2019-09-26 05:54:31 -07:00
|
|
|
void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
|
|
|
|
if (!UISettings::values.pause_when_in_background) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (state != Qt::ApplicationHidden && state != Qt::ApplicationInactive &&
|
|
|
|
state != Qt::ApplicationActive) {
|
|
|
|
LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state);
|
|
|
|
}
|
|
|
|
if (ui.action_Pause->isEnabled() &&
|
|
|
|
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
|
|
|
|
auto_paused = true;
|
|
|
|
OnPauseGame();
|
|
|
|
} else if (ui.action_Start->isEnabled() && auto_paused && state == Qt::ApplicationActive) {
|
|
|
|
auto_paused = false;
|
|
|
|
OnStartGame();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-19 11:50:58 -08:00
|
|
|
void GMainWindow::ConnectWidgetEvents() {
|
2018-01-18 17:03:13 -08:00
|
|
|
connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
|
2019-05-01 14:21:04 -07:00
|
|
|
connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
|
2018-08-20 21:46:40 -07:00
|
|
|
connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
|
2019-02-08 00:05:51 -08:00
|
|
|
connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this,
|
|
|
|
&GMainWindow::OnTransferableShaderCacheOpenFile);
|
2020-07-17 02:21:26 -07:00
|
|
|
connect(game_list, &GameList::RemoveInstalledEntryRequested, this,
|
|
|
|
&GMainWindow::OnGameListRemoveInstalledEntry);
|
|
|
|
connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile);
|
2018-09-19 19:09:23 -07:00
|
|
|
connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
|
|
|
|
connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
|
2018-08-29 06:42:53 -07:00
|
|
|
connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
|
|
|
|
&GMainWindow::OnGameListNavigateToGamedbEntry);
|
2019-05-01 14:21:04 -07:00
|
|
|
connect(game_list, &GameList::AddDirectory, this, &GMainWindow::OnGameListAddDirectory);
|
|
|
|
connect(game_list_placeholder, &GameListPlaceholder::AddDirectory, this,
|
|
|
|
&GMainWindow::OnGameListAddDirectory);
|
|
|
|
connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
|
|
|
|
|
2018-12-04 10:34:46 -08:00
|
|
|
connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
|
|
|
|
&GMainWindow::OnGameListOpenPerGameProperties);
|
2014-03-31 19:26:50 -07:00
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
connect(this, &GMainWindow::UpdateInstallProgress, this,
|
|
|
|
&GMainWindow::IncrementInstallProgress);
|
|
|
|
|
2018-01-18 17:03:13 -08:00
|
|
|
connect(this, &GMainWindow::EmulationStarting, render_window,
|
|
|
|
&GRenderWindow::OnEmulationStarting);
|
|
|
|
connect(this, &GMainWindow::EmulationStopping, render_window,
|
|
|
|
&GRenderWindow::OnEmulationStopping);
|
2017-02-19 14:34:47 -08:00
|
|
|
|
|
|
|
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
|
2017-02-18 02:26:57 -08:00
|
|
|
void GMainWindow::ConnectMenuEvents() {
|
|
|
|
// File
|
|
|
|
connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile);
|
2018-06-14 09:27:29 -07:00
|
|
|
connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder);
|
2018-08-09 18:33:13 -07:00
|
|
|
connect(ui.action_Install_File_NAND, &QAction::triggered, this,
|
|
|
|
&GMainWindow::OnMenuInstallToNAND);
|
2017-02-18 02:30:29 -08:00
|
|
|
connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close);
|
2018-10-23 16:28:17 -07:00
|
|
|
connect(ui.action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo);
|
2017-02-18 02:26:57 -08:00
|
|
|
|
|
|
|
// Emulation
|
|
|
|
connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame);
|
|
|
|
connect(ui.action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame);
|
|
|
|
connect(ui.action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame);
|
2018-09-16 11:05:51 -07:00
|
|
|
connect(ui.action_Report_Compatibility, &QAction::triggered, this,
|
|
|
|
&GMainWindow::OnMenuReportCompatibility);
|
2020-06-21 09:10:23 -07:00
|
|
|
connect(ui.action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage);
|
2020-06-25 14:44:41 -07:00
|
|
|
connect(ui.action_Open_Quickstart_Guide, &QAction::triggered, this,
|
2020-06-26 09:51:12 -07:00
|
|
|
&GMainWindow::OnOpenQuickstartGuide);
|
2020-06-26 17:14:29 -07:00
|
|
|
connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ);
|
2018-08-21 04:24:55 -07:00
|
|
|
connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); });
|
2017-02-18 02:26:57 -08:00
|
|
|
connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
|
2020-08-11 11:57:29 -07:00
|
|
|
connect(ui.action_Configure_Current_Game, &QAction::triggered, this,
|
|
|
|
&GMainWindow::OnConfigurePerGame);
|
2017-02-18 02:26:57 -08:00
|
|
|
|
|
|
|
// View
|
|
|
|
connect(ui.action_Single_Window_Mode, &QAction::triggered, this,
|
|
|
|
&GMainWindow::ToggleWindowMode);
|
2017-02-18 02:30:29 -08:00
|
|
|
connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this,
|
|
|
|
&GMainWindow::OnDisplayTitleBars);
|
2017-04-29 19:04:39 -07:00
|
|
|
connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
|
2017-02-18 12:09:14 -08:00
|
|
|
connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
|
2020-05-15 13:22:27 -07:00
|
|
|
connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize);
|
2018-01-14 10:15:45 -08:00
|
|
|
|
2018-01-16 06:50:33 -08:00
|
|
|
// Fullscreen
|
|
|
|
connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
|
|
|
|
|
2018-08-30 23:16:16 -07:00
|
|
|
// Movie
|
|
|
|
connect(ui.action_Capture_Screenshot, &QAction::triggered, this,
|
|
|
|
&GMainWindow::OnCaptureScreenshot);
|
|
|
|
|
2018-01-14 10:15:45 -08:00
|
|
|
// Help
|
2018-11-01 19:05:44 -07:00
|
|
|
connect(ui.action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
|
2018-09-23 18:35:32 -07:00
|
|
|
connect(ui.action_Rederive, &QAction::triggered, this,
|
2018-09-29 08:48:51 -07:00
|
|
|
std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
|
2018-01-14 10:15:45 -08:00
|
|
|
connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
|
2017-02-18 02:26:57 -08:00
|
|
|
}
|
|
|
|
|
2016-09-17 17:38:01 -07:00
|
|
|
void GMainWindow::OnDisplayTitleBars(bool show) {
|
2015-01-06 07:09:30 -08:00
|
|
|
QList<QDockWidget*> widgets = findChildren<QDockWidget*>();
|
|
|
|
|
|
|
|
if (show) {
|
2016-09-17 17:38:01 -07:00
|
|
|
for (QDockWidget* widget : widgets) {
|
2015-01-06 07:09:30 -08:00
|
|
|
QWidget* old = widget->titleBarWidget();
|
|
|
|
widget->setTitleBarWidget(nullptr);
|
|
|
|
if (old != nullptr)
|
|
|
|
delete old;
|
|
|
|
}
|
|
|
|
} else {
|
2016-09-17 17:38:01 -07:00
|
|
|
for (QDockWidget* widget : widgets) {
|
2015-01-06 07:09:30 -08:00
|
|
|
QWidget* old = widget->titleBarWidget();
|
|
|
|
widget->setTitleBarWidget(new QWidget());
|
|
|
|
if (old != nullptr)
|
|
|
|
delete old;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 14:00:34 -07:00
|
|
|
void GMainWindow::PreventOSSleep() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::AllowOSSleep() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
SetThreadExecutionState(ES_CONTINUOUS);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-02-16 22:32:22 -08:00
|
|
|
bool GMainWindow::LoadROM(const QString& filename) {
|
2015-07-28 09:43:18 -07:00
|
|
|
// Shutdown previous session if the emu thread is still active...
|
|
|
|
if (emu_thread != nullptr)
|
|
|
|
ShutdownGame();
|
|
|
|
|
2020-01-21 11:40:53 -08:00
|
|
|
if (!render_window->InitRenderTarget()) {
|
2018-05-30 13:38:22 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-16 22:20:47 -08:00
|
|
|
Core::System& system{Core::System::GetInstance()};
|
2018-08-03 08:51:48 -07:00
|
|
|
system.SetFilesystem(vfs);
|
2016-01-07 11:33:54 -08:00
|
|
|
|
2019-03-11 16:39:48 -07:00
|
|
|
system.SetAppletFrontendSet({
|
2019-06-06 15:40:59 -07:00
|
|
|
nullptr, // Parental Controls
|
|
|
|
std::make_unique<QtErrorDisplay>(*this), //
|
|
|
|
nullptr, // Photo Viewer
|
|
|
|
std::make_unique<QtProfileSelector>(*this), //
|
|
|
|
std::make_unique<QtSoftwareKeyboard>(*this), //
|
|
|
|
std::make_unique<QtWebBrowser>(*this), //
|
|
|
|
nullptr, // E-Commerce
|
2019-03-11 16:39:48 -07:00
|
|
|
});
|
2018-11-09 17:38:11 -08:00
|
|
|
|
2020-02-25 07:12:46 -08:00
|
|
|
system.RegisterHostThread();
|
|
|
|
|
2018-08-01 17:59:42 -07:00
|
|
|
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
|
2014-04-03 18:24:07 -07:00
|
|
|
|
2018-09-04 11:44:40 -07:00
|
|
|
const auto drd_callout =
|
|
|
|
(UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
|
|
|
|
|
|
|
|
if (result == Core::System::ResultStatus::Success &&
|
|
|
|
system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory &&
|
|
|
|
drd_callout) {
|
|
|
|
UISettings::values.callout_flags |= static_cast<u32>(CalloutFlag::DRDDeprecation);
|
2018-08-30 13:59:49 -07:00
|
|
|
QMessageBox::warning(
|
|
|
|
this, tr("Warning Outdated Game Format"),
|
|
|
|
tr("You are using the deconstructed ROM directory format for this game, which is an "
|
|
|
|
"outdated format that has been superseded by others such as NCA, NAX, XCI, or "
|
2018-09-04 11:44:40 -07:00
|
|
|
"NSP. Deconstructed ROM directories lack icons, metadata, and update "
|
|
|
|
"support.<br><br>For an explanation of the various Switch formats yuzu supports, <a "
|
2018-08-30 13:59:49 -07:00
|
|
|
"href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>check out our "
|
2018-09-04 11:44:40 -07:00
|
|
|
"wiki</a>. This message will not be shown again."));
|
2018-08-30 13:59:49 -07:00
|
|
|
}
|
|
|
|
|
2016-11-04 20:14:38 -07:00
|
|
|
if (result != Core::System::ResultStatus::Success) {
|
|
|
|
switch (result) {
|
|
|
|
case Core::System::ResultStatus::ErrorGetLoader:
|
2018-07-02 09:13:26 -07:00
|
|
|
LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filename.toStdString());
|
2016-11-04 20:14:38 -07:00
|
|
|
QMessageBox::critical(this, tr("Error while loading ROM!"),
|
2016-12-16 22:20:47 -08:00
|
|
|
tr("The ROM format is not supported."));
|
2016-11-04 20:14:38 -07:00
|
|
|
break;
|
2017-03-08 17:21:31 -08:00
|
|
|
case Core::System::ResultStatus::ErrorVideoCore:
|
|
|
|
QMessageBox::critical(
|
2018-08-03 09:55:58 -07:00
|
|
|
this, tr("An error occurred initializing the video core."),
|
2018-01-13 15:49:16 -08:00
|
|
|
tr("yuzu has encountered an error while running the video core, please see the "
|
2017-03-08 17:21:31 -08:00
|
|
|
"log for more details."
|
|
|
|
"For more information on accessing the log, please see the following page: "
|
|
|
|
"<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
|
|
|
|
"to "
|
|
|
|
"Upload the Log File</a>."
|
|
|
|
"Ensure that you have the latest graphics drivers for your GPU."));
|
|
|
|
|
2017-03-08 13:28:30 -08:00
|
|
|
break;
|
|
|
|
|
2016-01-07 09:36:10 -08:00
|
|
|
default:
|
2018-08-09 18:06:44 -07:00
|
|
|
if (static_cast<u32>(result) >
|
|
|
|
static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
|
|
|
|
const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
|
|
|
|
const u16 error_id = static_cast<u16>(result) - loader_id;
|
2020-04-13 17:56:22 -07:00
|
|
|
const std::string error_code = fmt::format("({:04X}-{:04X})", loader_id, error_id);
|
|
|
|
LOG_CRITICAL(Frontend, "Failed to load ROM! {}", error_code);
|
2018-08-09 18:06:44 -07:00
|
|
|
QMessageBox::critical(
|
2020-04-13 17:56:22 -07:00
|
|
|
this,
|
|
|
|
tr("Error while loading ROM! ").append(QString::fromStdString(error_code)),
|
2018-08-09 18:06:44 -07:00
|
|
|
QString::fromStdString(fmt::format(
|
2020-04-13 17:56:22 -07:00
|
|
|
"{}<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the "
|
|
|
|
"yuzu quickstart guide</a> to redump your files.<br>You can refer "
|
|
|
|
"to the yuzu wiki</a> or the yuzu Discord</a> for help.",
|
|
|
|
static_cast<Loader::ResultStatus>(error_id))));
|
2018-08-09 18:06:44 -07:00
|
|
|
} else {
|
|
|
|
QMessageBox::critical(
|
|
|
|
this, tr("Error while loading ROM!"),
|
|
|
|
tr("An unknown error occurred. Please see the log for more details."));
|
|
|
|
}
|
2016-01-07 09:36:10 -08:00
|
|
|
break;
|
|
|
|
}
|
2016-01-07 11:33:54 -08:00
|
|
|
return false;
|
2014-04-03 18:24:07 -07:00
|
|
|
}
|
2018-08-21 04:12:45 -07:00
|
|
|
game_path = filename;
|
|
|
|
|
2019-03-02 12:20:49 -08:00
|
|
|
system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "Qt");
|
2016-01-07 11:33:54 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-25 07:42:02 -08:00
|
|
|
void GMainWindow::SelectAndSetCurrentUser() {
|
|
|
|
QtProfileSelectionDialog dialog(this);
|
|
|
|
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
|
|
|
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
|
|
|
dialog.setWindowModality(Qt::WindowModal);
|
|
|
|
|
2019-05-28 21:34:42 -07:00
|
|
|
if (dialog.exec() == QDialog::Rejected) {
|
|
|
|
return;
|
2018-12-25 07:42:02 -08:00
|
|
|
}
|
2019-05-28 21:34:42 -07:00
|
|
|
|
|
|
|
Settings::values.current_user = dialog.GetIndex();
|
2018-12-25 07:42:02 -08:00
|
|
|
}
|
|
|
|
|
2017-02-16 22:32:22 -08:00
|
|
|
void GMainWindow::BootGame(const QString& filename) {
|
2018-07-02 09:13:26 -07:00
|
|
|
LOG_INFO(Frontend, "yuzu starting...");
|
2016-03-06 02:22:45 -08:00
|
|
|
StoreRecentFile(filename); // Put the filename on top of the list
|
2016-01-07 11:33:54 -08:00
|
|
|
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
u64 title_id{0};
|
|
|
|
|
|
|
|
const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
|
|
|
|
const auto loader = Loader::GetLoader(v_file);
|
|
|
|
if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
|
|
|
|
// Load per game settings
|
|
|
|
Config per_game_config(fmt::format("{:016X}.ini", title_id), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Settings::LogSettings();
|
|
|
|
|
2018-12-25 07:42:02 -08:00
|
|
|
if (UISettings::values.select_user_on_boot) {
|
|
|
|
SelectAndSetCurrentUser();
|
|
|
|
}
|
2016-01-07 11:33:54 -08:00
|
|
|
|
2016-11-19 17:40:04 -08:00
|
|
|
if (!LoadROM(filename))
|
2016-01-07 11:33:54 -08:00
|
|
|
return;
|
|
|
|
|
2015-04-28 21:01:41 -07:00
|
|
|
// Create and start the emulation thread
|
2020-03-24 19:58:49 -07:00
|
|
|
emu_thread = std::make_unique<EmuThread>();
|
2015-04-30 16:46:50 -07:00
|
|
|
emit EmulationStarting(emu_thread.get());
|
2015-04-16 15:35:09 -07:00
|
|
|
emu_thread->start();
|
2014-04-21 20:15:17 -07:00
|
|
|
|
2018-01-18 17:03:13 -08:00
|
|
|
connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
|
2016-09-17 17:38:01 -07:00
|
|
|
// BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views
|
|
|
|
// before the CPU continues
|
2018-01-18 17:03:13 -08:00
|
|
|
connect(emu_thread.get(), &EmuThread::DebugModeEntered, waitTreeWidget,
|
|
|
|
&WaitTreeWidget::OnDebugModeEntered, Qt::BlockingQueuedConnection);
|
|
|
|
connect(emu_thread.get(), &EmuThread::DebugModeLeft, waitTreeWidget,
|
|
|
|
&WaitTreeWidget::OnDebugModeLeft, Qt::BlockingQueuedConnection);
|
2015-04-28 21:01:41 -07:00
|
|
|
|
2019-01-21 11:38:23 -08:00
|
|
|
connect(emu_thread.get(), &EmuThread::LoadProgress, loading_screen,
|
|
|
|
&LoadingScreen::OnLoadProgress, Qt::QueuedConnection);
|
|
|
|
|
2015-04-28 21:01:41 -07:00
|
|
|
// Update the GUI
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
UpdateStatusButtons();
|
2015-08-31 21:35:33 -07:00
|
|
|
if (ui.action_Single_Window_Mode->isChecked()) {
|
|
|
|
game_list->hide();
|
2019-05-01 14:21:04 -07:00
|
|
|
game_list_placeholder->hide();
|
2015-08-31 21:35:33 -07:00
|
|
|
}
|
2017-02-20 16:36:44 -08:00
|
|
|
status_bar_update_timer.start(2000);
|
2020-01-28 14:59:30 -08:00
|
|
|
async_status_button->setDisabled(true);
|
2020-03-15 18:34:22 -07:00
|
|
|
multicore_status_button->setDisabled(true);
|
2020-01-28 14:59:30 -08:00
|
|
|
renderer_status_button->setDisabled(true);
|
2017-02-19 14:34:47 -08:00
|
|
|
|
2020-04-10 19:22:50 -07:00
|
|
|
if (UISettings::values.hide_mouse) {
|
|
|
|
mouse_hide_timer.start();
|
|
|
|
setMouseTracking(true);
|
|
|
|
ui.centralwidget->setMouseTracking(true);
|
|
|
|
}
|
|
|
|
|
2018-08-23 11:12:56 -07:00
|
|
|
std::string title_name;
|
2020-06-08 14:58:04 -07:00
|
|
|
std::string title_version;
|
2018-08-23 11:12:56 -07:00
|
|
|
const auto res = Core::System::GetInstance().GetGameName(title_name);
|
2018-09-03 15:57:52 -07:00
|
|
|
|
2020-06-08 14:58:04 -07:00
|
|
|
const auto metadata = FileSys::PatchManager(title_id).GetControlMetadata();
|
|
|
|
if (metadata.first != nullptr) {
|
|
|
|
title_version = metadata.first->GetVersionString();
|
|
|
|
title_name = metadata.first->GetApplicationName();
|
2018-09-03 15:57:52 -07:00
|
|
|
}
|
2020-06-08 14:58:04 -07:00
|
|
|
if (res != Loader::ResultStatus::Success || title_name.empty()) {
|
2020-08-15 05:33:16 -07:00
|
|
|
title_name = Common::FS::GetFilename(filename.toStdString());
|
2020-06-08 14:58:04 -07:00
|
|
|
}
|
|
|
|
LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version);
|
|
|
|
UpdateWindowTitle(title_name, title_version);
|
2018-08-23 11:12:56 -07:00
|
|
|
|
2019-01-16 23:01:00 -08:00
|
|
|
loading_screen->Prepare(Core::System::GetInstance().GetAppLoader());
|
|
|
|
loading_screen->show();
|
2015-04-28 21:01:41 -07:00
|
|
|
|
2015-08-31 18:30:06 -07:00
|
|
|
emulation_running = true;
|
2018-01-16 06:59:30 -08:00
|
|
|
if (ui.action_Fullscreen->isChecked()) {
|
|
|
|
ShowFullscreen();
|
|
|
|
}
|
2014-10-30 22:44:51 -07:00
|
|
|
OnStartGame();
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
|
2015-04-27 20:13:57 -07:00
|
|
|
void GMainWindow::ShutdownGame() {
|
2020-03-27 18:31:35 -07:00
|
|
|
if (!emulation_running) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ui.action_Fullscreen->isChecked()) {
|
|
|
|
HideFullscreen();
|
|
|
|
}
|
|
|
|
|
2019-09-03 14:00:34 -07:00
|
|
|
AllowOSSleep();
|
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
discord_rpc->Pause();
|
2015-04-30 16:46:50 -07:00
|
|
|
emu_thread->RequestStop();
|
2015-04-27 20:13:57 -07:00
|
|
|
|
2015-04-30 16:46:50 -07:00
|
|
|
emit EmulationStopping();
|
2015-04-28 21:01:41 -07:00
|
|
|
|
|
|
|
// Wait for emulation thread to complete and delete it
|
|
|
|
emu_thread->wait();
|
|
|
|
emu_thread = nullptr;
|
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
discord_rpc->Update();
|
|
|
|
|
2015-09-05 03:29:44 -07:00
|
|
|
// The emulation is stopped, so closing the window or not does not matter anymore
|
2018-01-18 17:03:13 -08:00
|
|
|
disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
|
2015-09-05 03:29:44 -07:00
|
|
|
|
2015-04-28 16:03:01 -07:00
|
|
|
// Update the GUI
|
2015-04-30 16:58:26 -07:00
|
|
|
ui.action_Start->setEnabled(false);
|
2015-07-26 07:38:51 -07:00
|
|
|
ui.action_Start->setText(tr("Start"));
|
2015-04-27 20:13:57 -07:00
|
|
|
ui.action_Pause->setEnabled(false);
|
|
|
|
ui.action_Stop->setEnabled(false);
|
2018-08-21 04:24:55 -07:00
|
|
|
ui.action_Restart->setEnabled(false);
|
2020-08-11 11:57:29 -07:00
|
|
|
ui.action_Configure_Current_Game->setEnabled(false);
|
2018-09-16 11:05:51 -07:00
|
|
|
ui.action_Report_Compatibility->setEnabled(false);
|
2018-10-23 16:28:17 -07:00
|
|
|
ui.action_Load_Amiibo->setEnabled(false);
|
2018-08-30 23:16:16 -07:00
|
|
|
ui.action_Capture_Screenshot->setEnabled(false);
|
2015-04-27 20:13:57 -07:00
|
|
|
render_window->hide();
|
2019-01-16 23:01:00 -08:00
|
|
|
loading_screen->hide();
|
|
|
|
loading_screen->Clear();
|
2019-05-01 14:21:04 -07:00
|
|
|
if (game_list->isEmpty())
|
|
|
|
game_list_placeholder->show();
|
|
|
|
else
|
|
|
|
game_list->show();
|
2017-04-29 19:04:39 -07:00
|
|
|
game_list->setFilterFocus();
|
2019-05-08 22:41:33 -07:00
|
|
|
|
2020-04-10 19:22:50 -07:00
|
|
|
setMouseTracking(false);
|
|
|
|
ui.centralwidget->setMouseTracking(false);
|
|
|
|
|
2019-05-08 22:41:33 -07:00
|
|
|
UpdateWindowTitle();
|
2015-08-31 18:30:06 -07:00
|
|
|
|
2017-02-19 14:34:47 -08:00
|
|
|
// Disable status bar updates
|
|
|
|
status_bar_update_timer.stop();
|
2020-07-09 20:36:38 -07:00
|
|
|
shader_building_label->setVisible(false);
|
2017-02-19 14:34:47 -08:00
|
|
|
emu_speed_label->setVisible(false);
|
|
|
|
game_fps_label->setVisible(false);
|
|
|
|
emu_frametime_label->setVisible(false);
|
2020-01-28 14:59:30 -08:00
|
|
|
async_status_button->setEnabled(true);
|
2020-03-15 18:34:22 -07:00
|
|
|
multicore_status_button->setEnabled(true);
|
2020-01-28 14:59:30 -08:00
|
|
|
#ifdef HAS_VULKAN
|
|
|
|
renderer_status_button->setEnabled(true);
|
|
|
|
#endif
|
2017-02-19 14:34:47 -08:00
|
|
|
|
2015-08-31 18:30:06 -07:00
|
|
|
emulation_running = false;
|
2018-08-21 04:12:45 -07:00
|
|
|
|
|
|
|
game_path.clear();
|
2020-02-17 12:49:52 -08:00
|
|
|
|
|
|
|
// When closing the game, destroy the GLWindow to clear the context after the game is closed
|
|
|
|
render_window->ReleaseRenderTarget();
|
2015-04-27 20:13:57 -07:00
|
|
|
}
|
|
|
|
|
2017-02-16 22:32:22 -08:00
|
|
|
void GMainWindow::StoreRecentFile(const QString& filename) {
|
|
|
|
UISettings::values.recent_files.prepend(filename);
|
2016-01-24 12:23:55 -08:00
|
|
|
UISettings::values.recent_files.removeDuplicates();
|
|
|
|
while (UISettings::values.recent_files.size() > max_recent_files_item) {
|
|
|
|
UISettings::values.recent_files.removeLast();
|
2015-09-07 18:00:08 -07:00
|
|
|
}
|
|
|
|
|
2015-08-17 13:50:52 -07:00
|
|
|
UpdateRecentFiles();
|
|
|
|
}
|
|
|
|
|
2015-07-28 09:43:18 -07:00
|
|
|
void GMainWindow::UpdateRecentFiles() {
|
2018-08-06 11:30:04 -07:00
|
|
|
const int num_recent_files =
|
|
|
|
std::min(UISettings::values.recent_files.size(), max_recent_files_item);
|
2015-07-28 09:43:18 -07:00
|
|
|
|
2018-08-06 11:30:04 -07:00
|
|
|
for (int i = 0; i < num_recent_files; i++) {
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString text = QStringLiteral("&%1. %2").arg(i + 1).arg(
|
2016-09-17 17:38:01 -07:00
|
|
|
QFileInfo(UISettings::values.recent_files[i]).fileName());
|
2015-07-28 09:43:18 -07:00
|
|
|
actions_recent_files[i]->setText(text);
|
2016-01-24 12:23:55 -08:00
|
|
|
actions_recent_files[i]->setData(UISettings::values.recent_files[i]);
|
|
|
|
actions_recent_files[i]->setToolTip(UISettings::values.recent_files[i]);
|
2015-07-28 09:43:18 -07:00
|
|
|
actions_recent_files[i]->setVisible(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = num_recent_files; j < max_recent_files_item; ++j) {
|
|
|
|
actions_recent_files[j]->setVisible(false);
|
|
|
|
}
|
|
|
|
|
2018-08-06 11:28:01 -07:00
|
|
|
// Enable the recent files menu if the list isn't empty
|
|
|
|
ui.menu_recent_files->setEnabled(num_recent_files != 0);
|
2015-07-28 09:43:18 -07:00
|
|
|
}
|
|
|
|
|
2015-08-31 21:35:33 -07:00
|
|
|
void GMainWindow::OnGameListLoadFile(QString game_path) {
|
2017-02-16 22:32:22 -08:00
|
|
|
BootGame(game_path);
|
2015-08-31 21:35:33 -07:00
|
|
|
}
|
|
|
|
|
2020-07-19 04:14:46 -07:00
|
|
|
void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target,
|
|
|
|
const std::string& game_path) {
|
2018-08-20 21:46:40 -07:00
|
|
|
std::string path;
|
2019-05-24 16:44:06 -07:00
|
|
|
QString open_target;
|
2020-04-14 12:08:13 -07:00
|
|
|
|
2020-07-19 20:52:06 -07:00
|
|
|
const auto [user_save_size, device_save_size] = [this, &program_id, &game_path] {
|
|
|
|
FileSys::PatchManager pm{program_id};
|
|
|
|
const auto control = pm.GetControlMetadata().first;
|
|
|
|
if (control != nullptr) {
|
|
|
|
return std::make_pair(control->GetDefaultNormalSaveSize(),
|
|
|
|
control->GetDeviceSaveDataSize());
|
|
|
|
} else {
|
|
|
|
const auto file = Core::GetGameFileFromPath(vfs, game_path);
|
|
|
|
const auto loader = Loader::GetLoader(file);
|
2020-04-14 12:08:13 -07:00
|
|
|
|
2020-07-19 20:52:06 -07:00
|
|
|
FileSys::NACP nacp{};
|
|
|
|
loader->ReadControlData(nacp);
|
|
|
|
return std::make_pair(nacp.GetDefaultNormalSaveSize(), nacp.GetDeviceSaveDataSize());
|
|
|
|
}
|
|
|
|
}();
|
2020-04-14 12:08:13 -07:00
|
|
|
|
2020-07-19 20:52:06 -07:00
|
|
|
const bool has_user_save{user_save_size > 0};
|
|
|
|
const bool has_device_save{device_save_size > 0};
|
2020-04-14 12:08:13 -07:00
|
|
|
|
|
|
|
ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?");
|
|
|
|
|
2018-08-20 21:46:40 -07:00
|
|
|
switch (target) {
|
|
|
|
case GameListOpenTarget::SaveData: {
|
2019-05-24 16:44:06 -07:00
|
|
|
open_target = tr("Save Data");
|
2020-08-15 05:33:16 -07:00
|
|
|
const std::string nand_dir = Common::FS::GetUserPath(Common::FS::UserPath::NANDDir);
|
2018-10-09 18:53:26 -07:00
|
|
|
|
2020-04-14 12:08:13 -07:00
|
|
|
if (has_user_save) {
|
|
|
|
// User save data
|
|
|
|
const auto select_profile = [this] {
|
|
|
|
QtProfileSelectionDialog dialog(this);
|
|
|
|
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
|
|
|
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
|
|
|
dialog.setWindowModality(Qt::WindowModal);
|
2018-12-25 07:52:43 -08:00
|
|
|
|
2020-04-14 12:08:13 -07:00
|
|
|
if (dialog.exec() == QDialog::Rejected) {
|
|
|
|
return -1;
|
|
|
|
}
|
2018-10-09 18:53:26 -07:00
|
|
|
|
2020-04-14 12:08:13 -07:00
|
|
|
return dialog.GetIndex();
|
|
|
|
};
|
2018-10-09 18:53:26 -07:00
|
|
|
|
2020-04-14 12:08:13 -07:00
|
|
|
const auto index = select_profile();
|
|
|
|
if (index == -1) {
|
|
|
|
return;
|
|
|
|
}
|
2018-10-09 18:53:26 -07:00
|
|
|
|
2020-04-14 12:08:13 -07:00
|
|
|
Service::Account::ProfileManager manager;
|
|
|
|
const auto user_id = manager.GetUser(static_cast<std::size_t>(index));
|
|
|
|
ASSERT(user_id);
|
|
|
|
path = nand_dir + FileSys::SaveDataFactory::GetFullPath(
|
|
|
|
FileSys::SaveDataSpaceId::NandUser,
|
|
|
|
FileSys::SaveDataType::SaveData, program_id, user_id->uuid, 0);
|
|
|
|
} else {
|
|
|
|
// Device save data
|
|
|
|
path = nand_dir + FileSys::SaveDataFactory::GetFullPath(
|
|
|
|
FileSys::SaveDataSpaceId::NandUser,
|
|
|
|
FileSys::SaveDataType::SaveData, program_id, {}, 0);
|
|
|
|
}
|
2018-10-09 18:53:26 -07:00
|
|
|
|
2020-08-15 05:33:16 -07:00
|
|
|
if (!Common::FS::Exists(path)) {
|
|
|
|
Common::FS::CreateFullPath(path);
|
|
|
|
Common::FS::CreateDir(path);
|
2018-10-09 18:53:26 -07:00
|
|
|
}
|
|
|
|
|
2018-08-20 21:46:40 -07:00
|
|
|
break;
|
|
|
|
}
|
2018-09-19 19:09:23 -07:00
|
|
|
case GameListOpenTarget::ModData: {
|
2019-05-24 16:44:06 -07:00
|
|
|
open_target = tr("Mod Data");
|
2020-08-15 05:33:16 -07:00
|
|
|
const auto load_dir = Common::FS::GetUserPath(Common::FS::UserPath::LoadDir);
|
2018-09-19 19:09:23 -07:00
|
|
|
path = fmt::format("{}{:016X}", load_dir, program_id);
|
|
|
|
break;
|
|
|
|
}
|
2018-08-20 21:46:40 -07:00
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString qpath = QString::fromStdString(path);
|
|
|
|
const QDir dir(qpath);
|
|
|
|
if (!dir.exists()) {
|
2019-05-24 16:44:06 -07:00
|
|
|
QMessageBox::warning(this, tr("Error Opening %1 Folder").arg(open_target),
|
2018-08-20 21:46:40 -07:00
|
|
|
tr("Folder does not exist!"));
|
|
|
|
return;
|
|
|
|
}
|
2019-05-24 16:44:06 -07:00
|
|
|
LOG_INFO(Frontend, "Opening {} path for program_id={:016x}", open_target.toStdString(),
|
|
|
|
program_id);
|
2018-08-20 21:46:40 -07:00
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
|
2016-12-15 01:56:32 -08:00
|
|
|
}
|
|
|
|
|
2019-02-08 00:05:51 -08:00
|
|
|
void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString shader_dir =
|
2020-08-15 05:33:16 -07:00
|
|
|
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir));
|
2020-07-17 02:21:26 -07:00
|
|
|
const QString transferable_shader_cache_folder_path =
|
2019-05-24 16:44:06 -07:00
|
|
|
shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable");
|
2019-02-08 05:18:41 -08:00
|
|
|
const QString transferable_shader_cache_file_path =
|
2020-07-17 02:21:26 -07:00
|
|
|
transferable_shader_cache_folder_path + QDir::separator() +
|
2019-04-03 20:58:56 -07:00
|
|
|
QString::fromStdString(fmt::format("{:016X}.bin", program_id));
|
2019-02-08 00:05:51 -08:00
|
|
|
|
2019-04-03 20:53:29 -07:00
|
|
|
if (!QFile::exists(transferable_shader_cache_file_path)) {
|
2019-04-03 21:06:32 -07:00
|
|
|
QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"),
|
|
|
|
tr("A shader cache for this title does not exist."));
|
2019-02-08 00:05:51 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Windows supports opening a folder with selecting a specified file in explorer. On every other
|
|
|
|
// OS we just open the transferable shader cache folder without preselecting the transferable
|
|
|
|
// shader cache file for the selected game.
|
|
|
|
#if defined(Q_OS_WIN)
|
2019-04-03 21:12:52 -07:00
|
|
|
const QString explorer = QStringLiteral("explorer");
|
2019-02-08 00:05:51 -08:00
|
|
|
QStringList param;
|
2019-02-08 05:18:41 -08:00
|
|
|
if (!QFileInfo(transferable_shader_cache_file_path).isDir()) {
|
2019-04-03 21:12:52 -07:00
|
|
|
param << QStringLiteral("/select,");
|
2019-02-08 05:18:41 -08:00
|
|
|
}
|
|
|
|
param << QDir::toNativeSeparators(transferable_shader_cache_file_path);
|
2019-02-08 00:05:51 -08:00
|
|
|
QProcess::startDetached(explorer, param);
|
|
|
|
#else
|
2020-07-17 02:21:26 -07:00
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(transferable_shader_cache_folder_path));
|
2019-02-08 00:05:51 -08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-09-25 15:04:22 -07:00
|
|
|
static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) {
|
|
|
|
std::size_t out = 0;
|
|
|
|
|
|
|
|
for (const auto& subdir : dir->GetSubdirectories()) {
|
|
|
|
out += 1 + CalculateRomFSEntrySize(subdir, full);
|
|
|
|
}
|
|
|
|
|
2018-09-25 15:06:35 -07:00
|
|
|
return out + (full ? dir->GetFiles().size() : 0);
|
2018-09-25 15:04:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src,
|
|
|
|
const FileSys::VirtualDir& dest, std::size_t block_size, bool full) {
|
|
|
|
if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
|
|
|
|
return false;
|
|
|
|
if (dialog.wasCanceled())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (full) {
|
|
|
|
for (const auto& file : src->GetFiles()) {
|
|
|
|
const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
|
|
|
|
if (!FileSys::VfsRawCopy(file, out, block_size))
|
|
|
|
return false;
|
|
|
|
dialog.setValue(dialog.value() + 1);
|
|
|
|
if (dialog.wasCanceled())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& dir : src->GetSubdirectories()) {
|
|
|
|
const auto out = dest->CreateSubdirectory(dir->GetName());
|
|
|
|
if (!RomFSRawCopy(dialog, dir, out, block_size, full))
|
|
|
|
return false;
|
|
|
|
dialog.setValue(dialog.value() + 1);
|
|
|
|
if (dialog.wasCanceled())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-17 02:21:26 -07:00
|
|
|
void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) {
|
2020-07-17 03:06:56 -07:00
|
|
|
const QString entry_type = [this, type] {
|
|
|
|
switch (type) {
|
|
|
|
case InstalledEntryType::Game:
|
|
|
|
return tr("Contents");
|
|
|
|
case InstalledEntryType::Update:
|
|
|
|
return tr("Update");
|
|
|
|
case InstalledEntryType::AddOnContent:
|
|
|
|
return tr("DLC");
|
|
|
|
default:
|
|
|
|
return QString{};
|
|
|
|
}
|
|
|
|
}();
|
2020-07-17 02:21:26 -07:00
|
|
|
|
|
|
|
if (QMessageBox::question(
|
|
|
|
this, tr("Remove Entry"), tr("Remove Installed Game %1?").arg(entry_type),
|
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case InstalledEntryType::Game:
|
2020-07-17 03:06:56 -07:00
|
|
|
RemoveBaseContent(program_id, entry_type);
|
2020-07-17 02:21:26 -07:00
|
|
|
[[fallthrough]];
|
|
|
|
case InstalledEntryType::Update:
|
2020-07-17 03:06:56 -07:00
|
|
|
RemoveUpdateContent(program_id, entry_type);
|
2020-07-17 03:14:13 -07:00
|
|
|
if (type != InstalledEntryType::Game) {
|
2020-07-17 02:21:26 -07:00
|
|
|
break;
|
|
|
|
}
|
2020-07-17 03:14:13 -07:00
|
|
|
[[fallthrough]];
|
2020-07-17 02:21:26 -07:00
|
|
|
case InstalledEntryType::AddOnContent:
|
2020-07-17 03:06:56 -07:00
|
|
|
RemoveAddOnContent(program_id, entry_type);
|
2020-07-17 02:21:26 -07:00
|
|
|
break;
|
|
|
|
}
|
2020-08-15 05:33:16 -07:00
|
|
|
Common::FS::DeleteDirRecursively(Common::FS::GetUserPath(Common::FS::UserPath::CacheDir) +
|
|
|
|
DIR_SEP + "game_list");
|
2020-07-20 07:30:56 -07:00
|
|
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
2020-07-17 02:21:26 -07:00
|
|
|
}
|
|
|
|
|
2020-07-17 03:06:56 -07:00
|
|
|
void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) {
|
2020-07-20 07:30:56 -07:00
|
|
|
const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
|
|
|
|
const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) ||
|
|
|
|
fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id);
|
2020-07-17 03:06:56 -07:00
|
|
|
|
|
|
|
if (res) {
|
|
|
|
QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
tr("Successfully removed the installed base game."));
|
|
|
|
} else {
|
|
|
|
QMessageBox::warning(
|
|
|
|
this, tr("Error Removing %1").arg(entry_type),
|
|
|
|
tr("The base game is not installed in the NAND and cannot be removed."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) {
|
2020-07-20 07:30:56 -07:00
|
|
|
const auto update_id = program_id | 0x800;
|
|
|
|
const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
|
|
|
|
const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
|
|
|
|
fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id);
|
2020-07-17 03:06:56 -07:00
|
|
|
|
|
|
|
if (res) {
|
|
|
|
QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
tr("Successfully removed the installed update."));
|
|
|
|
} else {
|
|
|
|
QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type),
|
|
|
|
tr("There is no update installed for this title."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) {
|
|
|
|
u32 count{};
|
2020-07-20 07:30:56 -07:00
|
|
|
const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
|
2020-07-17 03:06:56 -07:00
|
|
|
const auto dlc_entries = Core::System::GetInstance().GetContentProvider().ListEntriesFilter(
|
|
|
|
FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
|
|
|
|
|
|
|
for (const auto& entry : dlc_entries) {
|
|
|
|
if ((entry.title_id & DLC_BASE_TITLE_ID_MASK) == program_id) {
|
2020-07-20 07:30:56 -07:00
|
|
|
const auto res =
|
|
|
|
fs_controller.GetUserNANDContents()->RemoveExistingEntry(entry.title_id) ||
|
|
|
|
fs_controller.GetSDMCContents()->RemoveExistingEntry(entry.title_id);
|
2020-07-17 03:06:56 -07:00
|
|
|
if (res) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type),
|
|
|
|
tr("There are no DLC installed for this title."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
tr("Successfully removed %1 installed DLC.").arg(count));
|
|
|
|
}
|
|
|
|
|
2020-07-17 02:21:26 -07:00
|
|
|
void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target) {
|
2020-07-17 03:06:56 -07:00
|
|
|
const QString question = [this, target] {
|
|
|
|
switch (target) {
|
|
|
|
case GameListRemoveTarget::ShaderCache:
|
|
|
|
return tr("Delete Transferable Shader Cache?");
|
|
|
|
case GameListRemoveTarget::CustomConfiguration:
|
|
|
|
return tr("Remove Custom Game Configuration?");
|
|
|
|
default:
|
|
|
|
return QString{};
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
|
|
|
|
if (QMessageBox::question(this, tr("Remove File"), question, QMessageBox::Yes | QMessageBox::No,
|
|
|
|
QMessageBox::No) != QMessageBox::Yes) {
|
|
|
|
return;
|
|
|
|
}
|
2020-07-17 02:21:26 -07:00
|
|
|
|
|
|
|
switch (target) {
|
|
|
|
case GameListRemoveTarget::ShaderCache:
|
2020-07-17 03:06:56 -07:00
|
|
|
RemoveTransferableShaderCache(program_id);
|
2020-07-17 02:21:26 -07:00
|
|
|
break;
|
|
|
|
case GameListRemoveTarget::CustomConfiguration:
|
2020-07-17 03:06:56 -07:00
|
|
|
RemoveCustomConfiguration(program_id);
|
2020-07-17 02:21:26 -07:00
|
|
|
break;
|
|
|
|
}
|
2020-07-17 03:06:56 -07:00
|
|
|
}
|
2020-07-17 02:21:26 -07:00
|
|
|
|
2020-07-17 03:06:56 -07:00
|
|
|
void GMainWindow::RemoveTransferableShaderCache(u64 program_id) {
|
|
|
|
const QString shader_dir =
|
2020-08-15 05:33:16 -07:00
|
|
|
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::ShaderDir));
|
2020-07-17 03:06:56 -07:00
|
|
|
const QString transferable_shader_cache_folder_path =
|
|
|
|
shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable");
|
|
|
|
const QString transferable_shader_cache_file_path =
|
|
|
|
transferable_shader_cache_folder_path + QDir::separator() +
|
|
|
|
QString::fromStdString(fmt::format("{:016X}.bin", program_id));
|
|
|
|
|
|
|
|
if (!QFile::exists(transferable_shader_cache_file_path)) {
|
|
|
|
QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"),
|
|
|
|
tr("A shader cache for this title does not exist."));
|
2020-07-17 02:21:26 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-17 03:06:56 -07:00
|
|
|
if (QFile::remove(transferable_shader_cache_file_path)) {
|
|
|
|
QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
tr("Successfully removed the transferable shader cache."));
|
|
|
|
} else {
|
|
|
|
QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"),
|
|
|
|
tr("Failed to remove the transferable shader cache."));
|
2020-07-17 02:21:26 -07:00
|
|
|
}
|
2020-07-17 03:06:56 -07:00
|
|
|
}
|
2020-07-17 02:21:26 -07:00
|
|
|
|
2020-07-17 03:06:56 -07:00
|
|
|
void GMainWindow::RemoveCustomConfiguration(u64 program_id) {
|
|
|
|
const QString config_dir =
|
2020-08-15 05:33:16 -07:00
|
|
|
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir));
|
2020-07-17 03:06:56 -07:00
|
|
|
const QString custom_config_file_path =
|
|
|
|
config_dir + QString::fromStdString(fmt::format("{:016X}.ini", program_id));
|
|
|
|
|
|
|
|
if (!QFile::exists(custom_config_file_path)) {
|
|
|
|
QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
|
|
|
|
tr("A custom configuration for this title does not exist."));
|
|
|
|
return;
|
2020-07-17 02:21:26 -07:00
|
|
|
}
|
2020-07-17 03:06:56 -07:00
|
|
|
|
|
|
|
if (QFile::remove(custom_config_file_path)) {
|
|
|
|
QMessageBox::information(this, tr("Successfully Removed"),
|
|
|
|
tr("Successfully removed the custom game configuration."));
|
|
|
|
} else {
|
|
|
|
QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
|
|
|
|
tr("Failed to remove the custom game configuration."));
|
2020-07-17 02:21:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-19 19:09:23 -07:00
|
|
|
void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
|
2018-10-17 15:27:23 -07:00
|
|
|
const auto failed = [this] {
|
2018-09-19 19:09:23 -07:00
|
|
|
QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
|
|
|
|
tr("There was an error copying the RomFS files or the user "
|
|
|
|
"cancelled the operation."));
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto loader = Loader::GetLoader(vfs->OpenFile(game_path, FileSys::Mode::Read));
|
|
|
|
if (loader == nullptr) {
|
|
|
|
failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSys::VirtualFile file;
|
|
|
|
if (loader->ReadRomFS(file) != Loader::ResultStatus::Success) {
|
|
|
|
failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-04 09:40:53 -08:00
|
|
|
const auto& installed = Core::System::GetInstance().GetContentProvider();
|
2018-12-01 17:32:38 -08:00
|
|
|
const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
|
2018-10-17 15:27:23 -07:00
|
|
|
|
|
|
|
if (!romfs_title_id) {
|
|
|
|
failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto path = fmt::format(
|
2020-08-15 05:33:16 -07:00
|
|
|
"{}{:016X}/romfs", Common::FS::GetUserPath(Common::FS::UserPath::DumpDir), *romfs_title_id);
|
2018-10-17 15:27:23 -07:00
|
|
|
|
|
|
|
FileSys::VirtualFile romfs;
|
|
|
|
|
|
|
|
if (*romfs_title_id == program_id) {
|
2020-04-23 05:10:06 -07:00
|
|
|
const u64 ivfc_offset = loader->ReadRomFSIVFCOffset();
|
2020-04-23 05:05:50 -07:00
|
|
|
FileSys::PatchManager pm{program_id};
|
|
|
|
romfs = pm.PatchRomFS(file, ivfc_offset, FileSys::ContentRecordType::Program);
|
2018-10-17 15:27:23 -07:00
|
|
|
} else {
|
2018-12-01 17:32:38 -08:00
|
|
|
romfs = installed.GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
|
2018-10-17 15:27:23 -07:00
|
|
|
}
|
2018-09-19 19:09:23 -07:00
|
|
|
|
2018-09-23 18:50:16 -07:00
|
|
|
const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
|
2018-09-19 19:09:23 -07:00
|
|
|
if (extracted == nullptr) {
|
|
|
|
failed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::Mode::ReadWrite);
|
|
|
|
|
|
|
|
if (out == nullptr) {
|
|
|
|
failed();
|
2018-10-17 15:27:23 -07:00
|
|
|
vfs->DeleteDirectory(path);
|
2018-09-19 19:09:23 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
bool ok = false;
|
|
|
|
const QStringList selections{tr("Full"), tr("Skeleton")};
|
2018-09-19 19:09:23 -07:00
|
|
|
const auto res = QInputDialog::getItem(
|
|
|
|
this, tr("Select RomFS Dump Mode"),
|
|
|
|
tr("Please select the how you would like the RomFS dumped.<br>Full will copy all of the "
|
|
|
|
"files into the new directory while <br>skeleton will only create the directory "
|
|
|
|
"structure."),
|
2019-05-24 16:44:06 -07:00
|
|
|
selections, 0, false, &ok);
|
2018-10-17 15:27:23 -07:00
|
|
|
if (!ok) {
|
2018-09-19 19:09:23 -07:00
|
|
|
failed();
|
2018-10-17 15:27:23 -07:00
|
|
|
vfs->DeleteDirectory(path);
|
|
|
|
return;
|
|
|
|
}
|
2018-09-19 19:09:23 -07:00
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
const auto full = res == selections.constFirst();
|
2018-09-25 15:04:22 -07:00
|
|
|
const auto entry_size = CalculateRomFSEntrySize(extracted, full);
|
2018-09-19 19:09:23 -07:00
|
|
|
|
2018-11-06 06:22:24 -08:00
|
|
|
QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0,
|
|
|
|
static_cast<s32>(entry_size), this);
|
2018-09-19 19:09:23 -07:00
|
|
|
progress.setWindowModality(Qt::WindowModal);
|
|
|
|
progress.setMinimumDuration(100);
|
|
|
|
|
2018-09-25 15:04:22 -07:00
|
|
|
if (RomFSRawCopy(progress, extracted, out, 0x400000, full)) {
|
2018-09-19 19:09:23 -07:00
|
|
|
progress.close();
|
|
|
|
QMessageBox::information(this, tr("RomFS Extraction Succeeded!"),
|
|
|
|
tr("The operation completed successfully."));
|
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(path)));
|
|
|
|
} else {
|
|
|
|
progress.close();
|
|
|
|
failed();
|
2018-10-17 15:27:23 -07:00
|
|
|
vfs->DeleteDirectory(path);
|
2018-09-19 19:09:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::OnGameListCopyTID(u64 program_id) {
|
|
|
|
QClipboard* clipboard = QGuiApplication::clipboard();
|
|
|
|
clipboard->setText(QString::fromStdString(fmt::format("{:016X}", program_id)));
|
|
|
|
}
|
|
|
|
|
2018-09-09 16:09:37 -07:00
|
|
|
void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
|
2018-09-09 16:35:05 -07:00
|
|
|
const CompatibilityList& compatibility_list) {
|
2018-09-09 16:09:37 -07:00
|
|
|
const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
|
2018-08-29 06:42:53 -07:00
|
|
|
|
|
|
|
QString directory;
|
2019-05-24 16:44:06 -07:00
|
|
|
if (it != compatibility_list.end()) {
|
2018-08-29 06:42:53 -07:00
|
|
|
directory = it->second.second;
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
2018-08-29 06:42:53 -07:00
|
|
|
|
2019-05-24 16:44:06 -07:00
|
|
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory));
|
2018-08-29 06:42:53 -07:00
|
|
|
}
|
|
|
|
|
2019-05-03 10:21:57 -07:00
|
|
|
void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
|
2019-05-01 14:21:04 -07:00
|
|
|
QString path;
|
2019-05-04 18:07:09 -07:00
|
|
|
if (directory == QStringLiteral("SDMC")) {
|
2020-08-15 05:33:16 -07:00
|
|
|
path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) +
|
2019-05-04 18:07:09 -07:00
|
|
|
"Nintendo/Contents/registered");
|
|
|
|
} else if (directory == QStringLiteral("UserNAND")) {
|
2020-08-15 05:33:16 -07:00
|
|
|
path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
2019-05-04 16:52:17 -07:00
|
|
|
"user/Contents/registered");
|
2019-05-04 18:07:09 -07:00
|
|
|
} else if (directory == QStringLiteral("SysNAND")) {
|
2020-08-15 05:33:16 -07:00
|
|
|
path = QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
2019-05-04 16:52:17 -07:00
|
|
|
"system/Contents/registered");
|
2019-05-01 14:21:04 -07:00
|
|
|
} else {
|
|
|
|
path = directory;
|
|
|
|
}
|
|
|
|
if (!QFileInfo::exists(path)) {
|
|
|
|
QMessageBox::critical(this, tr("Error Opening %1").arg(path), tr("Folder does not exist!"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::OnGameListAddDirectory() {
|
2019-05-03 10:21:57 -07:00
|
|
|
const QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
|
2020-08-15 05:33:16 -07:00
|
|
|
if (dir_path.isEmpty()) {
|
2019-05-01 14:21:04 -07:00
|
|
|
return;
|
2020-08-15 05:33:16 -07:00
|
|
|
}
|
|
|
|
|
2019-05-01 14:21:04 -07:00
|
|
|
UISettings::GameDir game_dir{dir_path, false, true};
|
|
|
|
if (!UISettings::values.game_dirs.contains(game_dir)) {
|
|
|
|
UISettings::values.game_dirs.append(game_dir);
|
|
|
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
|
|
|
} else {
|
|
|
|
LOG_WARNING(Frontend, "Selected directory is already in the game list");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::OnGameListShowList(bool show) {
|
|
|
|
if (emulation_running && ui.action_Single_Window_Mode->isChecked())
|
|
|
|
return;
|
|
|
|
game_list->setVisible(show);
|
|
|
|
game_list_placeholder->setVisible(!show);
|
|
|
|
};
|
|
|
|
|
2018-12-04 10:34:46 -08:00
|
|
|
void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) {
|
|
|
|
u64 title_id{};
|
|
|
|
const auto v_file = Core::GetGameFileFromPath(vfs, file);
|
|
|
|
const auto loader = Loader::GetLoader(v_file);
|
|
|
|
if (loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
|
|
|
QMessageBox::information(this, tr("Properties"),
|
|
|
|
tr("The game properties could not be loaded."));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-11 11:57:29 -07:00
|
|
|
OpenPerGameConfiguration(title_id, file);
|
2018-12-04 10:34:46 -08:00
|
|
|
}
|
|
|
|
|
2015-07-28 09:43:18 -07:00
|
|
|
void GMainWindow::OnMenuLoadFile() {
|
2018-10-13 07:23:50 -07:00
|
|
|
const QString extensions =
|
2019-05-24 16:44:06 -07:00
|
|
|
QStringLiteral("*.")
|
|
|
|
.append(GameList::supported_file_extensions.join(QStringLiteral(" *.")))
|
|
|
|
.append(QStringLiteral(" main"));
|
2018-10-13 07:23:50 -07:00
|
|
|
const QString file_filter = tr("Switch Executable (%1);;All Files (*.*)",
|
|
|
|
"%1 is an identifier for the Switch executable file extensions.")
|
|
|
|
.arg(extensions);
|
|
|
|
const QString filename = QFileDialog::getOpenFileName(
|
|
|
|
this, tr("Load File"), UISettings::values.roms_path, file_filter);
|
|
|
|
|
|
|
|
if (filename.isEmpty()) {
|
|
|
|
return;
|
2015-04-28 16:03:01 -07:00
|
|
|
}
|
2018-10-13 07:23:50 -07:00
|
|
|
|
|
|
|
UISettings::values.roms_path = QFileInfo(filename).path();
|
|
|
|
BootGame(filename);
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
|
2018-06-14 09:27:29 -07:00
|
|
|
void GMainWindow::OnMenuLoadFolder() {
|
2018-08-06 11:02:31 -07:00
|
|
|
const QString dir_path =
|
|
|
|
QFileDialog::getExistingDirectory(this, tr("Open Extracted ROM Directory"));
|
2018-06-14 09:27:29 -07:00
|
|
|
|
2018-08-06 11:02:31 -07:00
|
|
|
if (dir_path.isNull()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QDir dir{dir_path};
|
2019-05-24 16:44:06 -07:00
|
|
|
const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files);
|
2018-06-14 14:25:40 -07:00
|
|
|
if (matching_main.size() == 1) {
|
2019-05-24 16:44:06 -07:00
|
|
|
BootGame(dir.path() + QDir::separator() + matching_main[0]);
|
2018-06-14 14:25:40 -07:00
|
|
|
} else {
|
|
|
|
QMessageBox::warning(this, tr("Invalid Directory Selected"),
|
|
|
|
tr("The directory you have selected does not contain a 'main' file."));
|
2018-06-14 09:27:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
void GMainWindow::IncrementInstallProgress() {
|
|
|
|
install_progress->setValue(install_progress->value() + 1);
|
|
|
|
}
|
|
|
|
|
2018-08-09 18:33:13 -07:00
|
|
|
void GMainWindow::OnMenuInstallToNAND() {
|
2018-08-09 20:10:32 -07:00
|
|
|
const QString file_filter =
|
2018-08-25 08:50:15 -07:00
|
|
|
tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive "
|
2020-04-16 20:27:38 -07:00
|
|
|
"(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge "
|
2018-08-09 18:33:13 -07:00
|
|
|
"Image (*.xci)");
|
2018-08-10 12:07:06 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
QStringList filenames = QFileDialog::getOpenFileNames(
|
|
|
|
this, tr("Install Files"), UISettings::values.roms_path, file_filter);
|
|
|
|
|
|
|
|
if (filenames.isEmpty()) {
|
2020-04-16 20:27:38 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
InstallDialog installDialog(this, filenames);
|
2020-04-16 20:27:38 -07:00
|
|
|
if (installDialog.exec() == QDialog::Rejected) {
|
2018-08-16 07:37:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
const QStringList files = installDialog.GetFiles();
|
2020-04-16 20:27:38 -07:00
|
|
|
|
2020-07-08 10:01:25 -07:00
|
|
|
if (files.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
int remaining = filenames.size();
|
|
|
|
|
|
|
|
// This would only overflow above 2^43 bytes (8.796 TB)
|
|
|
|
int total_size = 0;
|
|
|
|
for (const QString& file : files) {
|
|
|
|
total_size += static_cast<int>(QFile(file).size() / 0x1000);
|
|
|
|
}
|
|
|
|
if (total_size < 0) {
|
|
|
|
LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting.");
|
|
|
|
return;
|
|
|
|
}
|
2020-07-01 13:15:57 -07:00
|
|
|
|
|
|
|
QStringList new_files{}; // Newly installed files that do not yet exist in the NAND
|
|
|
|
QStringList overwritten_files{}; // Files that overwrote those existing in the NAND
|
2020-07-05 06:29:39 -07:00
|
|
|
QStringList failed_files{}; // Files that failed to install due to errors
|
2020-07-01 13:15:57 -07:00
|
|
|
|
|
|
|
ui.action_Install_File_NAND->setEnabled(false);
|
|
|
|
|
2020-07-27 18:02:08 -07:00
|
|
|
install_progress = new QProgressDialog(QString{}, tr("Cancel"), 0, total_size, this);
|
2020-07-05 06:29:39 -07:00
|
|
|
install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
|
|
|
|
~Qt::WindowMaximizeButtonHint);
|
|
|
|
install_progress->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
|
install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40);
|
|
|
|
install_progress->show();
|
2020-07-01 13:15:57 -07:00
|
|
|
|
|
|
|
for (const QString& file : files) {
|
2020-07-05 06:29:39 -07:00
|
|
|
install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining));
|
|
|
|
install_progress->setLabelText(
|
2020-07-01 13:15:57 -07:00
|
|
|
tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName()));
|
|
|
|
|
|
|
|
QFuture<InstallResult> future;
|
|
|
|
InstallResult result;
|
|
|
|
|
|
|
|
if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) ||
|
|
|
|
file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
2020-07-05 06:29:39 -07:00
|
|
|
|
|
|
|
future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); });
|
2020-07-01 13:15:57 -07:00
|
|
|
|
|
|
|
while (!future.isFinished()) {
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
result = future.result();
|
2020-07-05 06:29:39 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
} else {
|
2020-07-05 06:29:39 -07:00
|
|
|
result = InstallNCA(file);
|
2020-07-01 13:15:57 -07:00
|
|
|
}
|
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
switch (result) {
|
|
|
|
case InstallResult::Success:
|
|
|
|
new_files.append(QFileInfo(file).fileName());
|
|
|
|
break;
|
|
|
|
case InstallResult::Overwrite:
|
|
|
|
overwritten_files.append(QFileInfo(file).fileName());
|
|
|
|
break;
|
|
|
|
case InstallResult::Failure:
|
|
|
|
failed_files.append(QFileInfo(file).fileName());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
--remaining;
|
2020-07-01 13:15:57 -07:00
|
|
|
}
|
2020-04-16 20:27:38 -07:00
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
install_progress->close();
|
2020-07-01 13:15:57 -07:00
|
|
|
|
|
|
|
const QString install_results =
|
2020-07-27 18:02:08 -07:00
|
|
|
(new_files.isEmpty() ? QString{}
|
2020-07-01 13:15:57 -07:00
|
|
|
: tr("%n file(s) were newly installed\n", "", new_files.size())) +
|
|
|
|
(overwritten_files.isEmpty()
|
2020-07-27 18:02:08 -07:00
|
|
|
? QString{}
|
2020-07-01 13:15:57 -07:00
|
|
|
: tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
|
2020-07-27 18:02:08 -07:00
|
|
|
(failed_files.isEmpty() ? QString{}
|
2020-07-01 13:15:57 -07:00
|
|
|
: tr("%n file(s) failed to install\n", "", failed_files.size()));
|
|
|
|
|
|
|
|
QMessageBox::information(this, tr("Install Results"), install_results);
|
2020-08-15 05:33:16 -07:00
|
|
|
Common::FS::DeleteDirRecursively(Common::FS::GetUserPath(Common::FS::UserPath::CacheDir) +
|
|
|
|
DIR_SEP + "game_list");
|
2020-07-20 07:30:56 -07:00
|
|
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
2020-07-01 13:15:57 -07:00
|
|
|
ui.action_Install_File_NAND->setEnabled(true);
|
|
|
|
}
|
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
|
|
|
|
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
|
|
|
|
const FileSys::VirtualFile& dest, std::size_t block_size) {
|
2020-04-16 20:27:38 -07:00
|
|
|
if (src == nullptr || dest == nullptr) {
|
2018-08-10 12:07:06 -07:00
|
|
|
return false;
|
2020-04-16 20:27:38 -07:00
|
|
|
}
|
|
|
|
if (!dest->Resize(src->GetSize())) {
|
2018-08-10 12:07:06 -07:00
|
|
|
return false;
|
2020-04-16 20:27:38 -07:00
|
|
|
}
|
2018-08-10 12:07:06 -07:00
|
|
|
|
2018-08-16 07:28:03 -07:00
|
|
|
std::array<u8, 0x1000> buffer{};
|
2018-08-10 12:07:06 -07:00
|
|
|
|
2018-09-15 06:21:06 -07:00
|
|
|
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
2020-07-05 06:29:39 -07:00
|
|
|
if (install_progress->wasCanceled()) {
|
2018-08-10 12:07:06 -07:00
|
|
|
dest->Resize(0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
emit UpdateInstallProgress();
|
|
|
|
|
2018-08-10 12:07:06 -07:00
|
|
|
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
|
|
|
dest->Write(buffer.data(), read, i);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
std::shared_ptr<FileSys::NSP> nsp;
|
|
|
|
if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) {
|
|
|
|
nsp = std::make_shared<FileSys::NSP>(
|
|
|
|
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
|
|
|
if (nsp->IsExtractedType()) {
|
|
|
|
return InstallResult::Failure;
|
2020-04-16 20:27:38 -07:00
|
|
|
}
|
2020-07-01 13:15:57 -07:00
|
|
|
} else {
|
|
|
|
const auto xci = std::make_shared<FileSys::XCI>(
|
|
|
|
vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
|
|
|
nsp = xci->GetSecurePartitionNSP();
|
|
|
|
}
|
2018-08-11 20:01:38 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
if (nsp->GetStatus() != Loader::ResultStatus::Success) {
|
|
|
|
return InstallResult::Failure;
|
|
|
|
}
|
|
|
|
const auto res =
|
|
|
|
Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry(
|
2020-07-05 06:29:39 -07:00
|
|
|
*nsp, true, qt_raw_copy);
|
2020-07-01 13:15:57 -07:00
|
|
|
if (res == FileSys::InstallResult::Success) {
|
|
|
|
return InstallResult::Success;
|
2020-07-12 09:28:18 -07:00
|
|
|
} else if (res == FileSys::InstallResult::OverwriteExisting) {
|
2020-07-05 06:29:39 -07:00
|
|
|
return InstallResult::Overwrite;
|
2020-07-01 13:15:57 -07:00
|
|
|
} else {
|
|
|
|
return InstallResult::Failure;
|
|
|
|
}
|
|
|
|
}
|
2018-08-11 20:01:38 -07:00
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
InstallResult GMainWindow::InstallNCA(const QString& filename) {
|
|
|
|
const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
|
|
|
|
const FileSys::VirtualFile& dest, std::size_t block_size) {
|
2020-07-01 13:15:57 -07:00
|
|
|
if (src == nullptr || dest == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!dest->Resize(src->GetSize())) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-11 20:01:38 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
std::array<u8, 0x1000> buffer{};
|
2018-08-25 08:50:04 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
|
2020-07-05 06:29:39 -07:00
|
|
|
if (install_progress->wasCanceled()) {
|
2020-07-01 13:15:57 -07:00
|
|
|
dest->Resize(0);
|
|
|
|
return false;
|
2020-04-16 20:27:38 -07:00
|
|
|
}
|
2018-08-09 18:33:13 -07:00
|
|
|
|
2020-07-05 06:29:39 -07:00
|
|
|
emit UpdateInstallProgress();
|
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
const auto read = src->Read(buffer.data(), buffer.size(), i);
|
|
|
|
dest->Write(buffer.data(), read, i);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
2018-09-27 06:19:53 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
const auto nca =
|
|
|
|
std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read));
|
|
|
|
const auto id = nca->GetStatus();
|
2018-08-16 07:37:56 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
// Game updates necessary are missing base RomFS
|
|
|
|
if (id != Loader::ResultStatus::Success &&
|
|
|
|
id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
|
|
|
return InstallResult::Failure;
|
|
|
|
}
|
2020-04-16 20:27:38 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
const QStringList tt_options{tr("System Application"),
|
|
|
|
tr("System Archive"),
|
|
|
|
tr("System Application Update"),
|
|
|
|
tr("Firmware Package (Type A)"),
|
|
|
|
tr("Firmware Package (Type B)"),
|
|
|
|
tr("Game"),
|
|
|
|
tr("Game Update"),
|
|
|
|
tr("Game DLC"),
|
|
|
|
tr("Delta Title")};
|
|
|
|
bool ok;
|
|
|
|
const auto item = QInputDialog::getItem(
|
|
|
|
this, tr("Select NCA Install Type..."),
|
|
|
|
tr("Please select the type of title you would like to install this NCA as:\n(In "
|
|
|
|
"most instances, the default 'Game' is fine.)"),
|
|
|
|
tt_options, 5, false, &ok);
|
|
|
|
|
|
|
|
auto index = tt_options.indexOf(item);
|
|
|
|
if (!ok || index == -1) {
|
|
|
|
QMessageBox::warning(this, tr("Failed to Install"),
|
|
|
|
tr("The title type you selected for the NCA is invalid."));
|
|
|
|
return InstallResult::Failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If index is equal to or past Game, add the jump in TitleType.
|
|
|
|
if (index >= 5) {
|
|
|
|
index += static_cast<size_t>(FileSys::TitleType::Application) -
|
|
|
|
static_cast<size_t>(FileSys::TitleType::FirmwarePackageB);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSys::InstallResult res;
|
|
|
|
if (index >= static_cast<s32>(FileSys::TitleType::Application)) {
|
|
|
|
res = Core::System::GetInstance()
|
|
|
|
.GetFileSystemController()
|
|
|
|
.GetUserNANDContents()
|
2020-07-05 06:29:39 -07:00
|
|
|
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
2020-07-01 13:15:57 -07:00
|
|
|
} else {
|
|
|
|
res = Core::System::GetInstance()
|
|
|
|
.GetFileSystemController()
|
|
|
|
.GetSystemNANDContents()
|
2020-07-05 06:29:39 -07:00
|
|
|
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
2020-07-01 13:15:57 -07:00
|
|
|
}
|
2020-04-16 20:27:38 -07:00
|
|
|
|
2020-07-01 13:15:57 -07:00
|
|
|
if (res == FileSys::InstallResult::Success) {
|
|
|
|
return InstallResult::Success;
|
2020-07-12 09:28:18 -07:00
|
|
|
} else if (res == FileSys::InstallResult::OverwriteExisting) {
|
2020-07-05 06:29:39 -07:00
|
|
|
return InstallResult::Overwrite;
|
2020-07-01 13:15:57 -07:00
|
|
|
} else {
|
|
|
|
return InstallResult::Failure;
|
2018-08-09 18:33:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-28 09:43:18 -07:00
|
|
|
void GMainWindow::OnMenuRecentFile() {
|
|
|
|
QAction* action = qobject_cast<QAction*>(sender());
|
|
|
|
assert(action);
|
|
|
|
|
2018-08-06 11:12:57 -07:00
|
|
|
const QString filename = action->data().toString();
|
|
|
|
if (QFileInfo::exists(filename)) {
|
2017-02-16 22:32:22 -08:00
|
|
|
BootGame(filename);
|
2015-07-28 09:43:18 -07:00
|
|
|
} else {
|
|
|
|
// Display an error message and remove the file from the list.
|
2016-09-17 17:38:01 -07:00
|
|
|
QMessageBox::information(this, tr("File not found"),
|
|
|
|
tr("File \"%1\" not found").arg(filename));
|
2015-07-28 09:43:18 -07:00
|
|
|
|
2016-01-24 12:23:55 -08:00
|
|
|
UISettings::values.recent_files.removeOne(filename);
|
2015-08-17 13:50:52 -07:00
|
|
|
UpdateRecentFiles();
|
2015-07-28 09:43:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::OnStartGame() {
|
2019-09-03 14:00:34 -07:00
|
|
|
PreventOSSleep();
|
|
|
|
|
2015-04-28 16:03:01 -07:00
|
|
|
emu_thread->SetRunning(true);
|
2018-11-11 13:39:25 -08:00
|
|
|
|
|
|
|
qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
|
2018-11-11 17:16:38 -08:00
|
|
|
"Core::Frontend::SoftwareKeyboardParameters");
|
2017-03-08 13:28:30 -08:00
|
|
|
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
|
2017-04-12 22:18:54 -07:00
|
|
|
qRegisterMetaType<std::string>("std::string");
|
2018-11-11 17:16:38 -08:00
|
|
|
qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
|
2018-12-24 13:23:31 -08:00
|
|
|
qRegisterMetaType<std::string_view>("std::string_view");
|
2018-11-11 13:39:25 -08:00
|
|
|
|
2018-01-18 17:03:13 -08:00
|
|
|
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
|
2014-04-03 18:24:07 -07:00
|
|
|
|
|
|
|
ui.action_Start->setEnabled(false);
|
2015-07-26 07:38:51 -07:00
|
|
|
ui.action_Start->setText(tr("Continue"));
|
|
|
|
|
2014-04-03 18:24:07 -07:00
|
|
|
ui.action_Pause->setEnabled(true);
|
|
|
|
ui.action_Stop->setEnabled(true);
|
2018-08-28 06:16:03 -07:00
|
|
|
ui.action_Restart->setEnabled(true);
|
2020-08-11 11:57:29 -07:00
|
|
|
ui.action_Configure_Current_Game->setEnabled(true);
|
2018-09-16 11:05:51 -07:00
|
|
|
ui.action_Report_Compatibility->setEnabled(true);
|
|
|
|
|
|
|
|
discord_rpc->Update();
|
2018-10-23 16:28:17 -07:00
|
|
|
ui.action_Load_Amiibo->setEnabled(true);
|
2018-08-30 23:16:16 -07:00
|
|
|
ui.action_Capture_Screenshot->setEnabled(true);
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
|
2015-07-28 09:43:18 -07:00
|
|
|
void GMainWindow::OnPauseGame() {
|
2015-04-28 16:03:01 -07:00
|
|
|
emu_thread->SetRunning(false);
|
2014-04-03 18:24:07 -07:00
|
|
|
|
|
|
|
ui.action_Start->setEnabled(true);
|
|
|
|
ui.action_Pause->setEnabled(false);
|
|
|
|
ui.action_Stop->setEnabled(true);
|
2018-08-30 23:16:16 -07:00
|
|
|
ui.action_Capture_Screenshot->setEnabled(false);
|
2019-09-03 14:00:34 -07:00
|
|
|
|
|
|
|
AllowOSSleep();
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
|
2015-04-16 20:31:14 -07:00
|
|
|
void GMainWindow::OnStopGame() {
|
2019-09-21 19:46:53 -07:00
|
|
|
Core::System& system{Core::System::GetInstance()};
|
|
|
|
if (system.GetExitLock() && !ConfirmForceLockedExit()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-27 20:13:57 -07:00
|
|
|
ShutdownGame();
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
|
|
|
|
Settings::RestoreGlobalState();
|
|
|
|
UpdateStatusButtons();
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
|
2019-01-16 23:01:00 -08:00
|
|
|
void GMainWindow::OnLoadComplete() {
|
2019-01-21 08:20:16 -08:00
|
|
|
loading_screen->OnLoadComplete();
|
2019-01-16 23:01:00 -08:00
|
|
|
}
|
|
|
|
|
2019-03-11 16:45:22 -07:00
|
|
|
void GMainWindow::ErrorDisplayDisplayError(QString body) {
|
|
|
|
QMessageBox::critical(this, tr("Error Display"), body);
|
|
|
|
emit ErrorDisplayFinished();
|
|
|
|
}
|
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
void GMainWindow::OnMenuReportCompatibility() {
|
|
|
|
if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) {
|
|
|
|
CompatDB compatdb{this};
|
|
|
|
compatdb.exec();
|
|
|
|
} else {
|
|
|
|
QMessageBox::critical(
|
|
|
|
this, tr("Missing yuzu Account"),
|
|
|
|
tr("In order to submit a game compatibility test case, you must link your yuzu "
|
|
|
|
"account.<br><br/>To link your yuzu account, go to Emulation > Configuration "
|
|
|
|
"> "
|
|
|
|
"Web."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 14:32:43 -07:00
|
|
|
void GMainWindow::OpenURL(const QUrl& url) {
|
2020-06-25 14:02:33 -07:00
|
|
|
const bool open = QDesktopServices::openUrl(url);
|
2020-06-20 21:09:28 -07:00
|
|
|
if (!open) {
|
|
|
|
QMessageBox::warning(this, tr("Error opening URL"),
|
2020-06-25 14:31:01 -07:00
|
|
|
tr("Unable to open the URL \"%1\".").arg(url.toString()));
|
2020-06-20 21:09:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 14:02:33 -07:00
|
|
|
void GMainWindow::OnOpenModsPage() {
|
2020-06-25 14:31:01 -07:00
|
|
|
OpenURL(QUrl(QStringLiteral("https://github.com/yuzu-emu/yuzu/wiki/Switch-Mods")));
|
2020-06-25 14:02:33 -07:00
|
|
|
}
|
|
|
|
|
2020-06-26 09:50:28 -07:00
|
|
|
void GMainWindow::OnOpenQuickstartGuide() {
|
2020-06-25 14:31:01 -07:00
|
|
|
OpenURL(QUrl(QStringLiteral("https://yuzu-emu.org/help/quickstart/")));
|
2020-06-25 14:02:33 -07:00
|
|
|
}
|
|
|
|
|
2020-06-26 17:14:29 -07:00
|
|
|
void GMainWindow::OnOpenFAQ() {
|
2020-06-25 14:31:01 -07:00
|
|
|
OpenURL(QUrl(QStringLiteral("https://yuzu-emu.org/wiki/faq/")));
|
2020-06-25 14:02:33 -07:00
|
|
|
}
|
|
|
|
|
2018-01-16 06:50:33 -08:00
|
|
|
void GMainWindow::ToggleFullscreen() {
|
|
|
|
if (!emulation_running) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ui.action_Fullscreen->isChecked()) {
|
2018-01-16 06:59:30 -08:00
|
|
|
ShowFullscreen();
|
2018-01-16 06:50:33 -08:00
|
|
|
} else {
|
2018-01-16 06:59:30 -08:00
|
|
|
HideFullscreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::ShowFullscreen() {
|
|
|
|
if (ui.action_Single_Window_Mode->isChecked()) {
|
|
|
|
UISettings::values.geometry = saveGeometry();
|
|
|
|
ui.menubar->hide();
|
|
|
|
statusBar()->hide();
|
|
|
|
showFullScreen();
|
|
|
|
} else {
|
|
|
|
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
|
|
|
|
render_window->showFullScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::HideFullscreen() {
|
|
|
|
if (ui.action_Single_Window_Mode->isChecked()) {
|
|
|
|
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
|
|
|
|
ui.menubar->show();
|
|
|
|
showNormal();
|
|
|
|
restoreGeometry(UISettings::values.geometry);
|
|
|
|
} else {
|
|
|
|
render_window->showNormal();
|
|
|
|
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
2018-01-16 06:50:33 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-16 15:35:09 -07:00
|
|
|
void GMainWindow::ToggleWindowMode() {
|
|
|
|
if (ui.action_Single_Window_Mode->isChecked()) {
|
|
|
|
// Render in the main window...
|
2014-04-21 20:15:17 -07:00
|
|
|
render_window->BackupGeometry();
|
|
|
|
ui.horizontalLayout->addWidget(render_window);
|
2020-03-26 11:36:49 -07:00
|
|
|
render_window->setFocusPolicy(Qt::StrongFocus);
|
2015-08-31 18:30:06 -07:00
|
|
|
if (emulation_running) {
|
|
|
|
render_window->setVisible(true);
|
|
|
|
render_window->setFocus();
|
2015-10-06 12:20:26 -07:00
|
|
|
game_list->hide();
|
2015-08-31 18:30:06 -07:00
|
|
|
}
|
2015-04-16 15:35:09 -07:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// Render in a separate window...
|
|
|
|
ui.horizontalLayout->removeWidget(render_window);
|
|
|
|
render_window->setParent(nullptr);
|
|
|
|
render_window->setFocusPolicy(Qt::NoFocus);
|
2015-08-31 18:30:06 -07:00
|
|
|
if (emulation_running) {
|
|
|
|
render_window->setVisible(true);
|
|
|
|
render_window->RestoreGeometry();
|
2015-08-31 21:35:33 -07:00
|
|
|
game_list->show();
|
2015-08-31 18:30:06 -07:00
|
|
|
}
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-15 13:22:27 -07:00
|
|
|
void GMainWindow::ResetWindowSize() {
|
|
|
|
const auto aspect_ratio = Layout::EmulationAspectRatio(
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()),
|
2020-05-15 13:22:27 -07:00
|
|
|
static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width);
|
|
|
|
if (!ui.action_Single_Window_Mode->isChecked()) {
|
|
|
|
render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio,
|
|
|
|
Layout::ScreenUndocked::Height);
|
|
|
|
} else {
|
|
|
|
resize(Layout::ScreenUndocked::Height / aspect_ratio,
|
|
|
|
Layout::ScreenUndocked::Height + menuBar()->height() +
|
|
|
|
(ui.action_Show_Status_Bar->isChecked() ? statusBar()->height() : 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-28 09:43:18 -07:00
|
|
|
void GMainWindow::OnConfigure() {
|
2019-05-25 21:39:23 -07:00
|
|
|
const auto old_theme = UISettings::values.theme;
|
2018-09-16 11:05:51 -07:00
|
|
|
const bool old_discord_presence = UISettings::values.enable_discord_presence;
|
2018-11-03 17:38:39 -07:00
|
|
|
|
2019-05-25 21:39:23 -07:00
|
|
|
ConfigureDialog configure_dialog(this, hotkey_registry);
|
2020-01-25 15:26:07 -08:00
|
|
|
connect(&configure_dialog, &ConfigureDialog::LanguageChanged, this,
|
|
|
|
&GMainWindow::OnLanguageChanged);
|
|
|
|
|
2019-05-25 21:39:23 -07:00
|
|
|
const auto result = configure_dialog.exec();
|
|
|
|
if (result != QDialog::Accepted) {
|
|
|
|
return;
|
|
|
|
}
|
2018-11-03 17:38:39 -07:00
|
|
|
|
2019-05-25 21:39:23 -07:00
|
|
|
configure_dialog.ApplyConfiguration();
|
|
|
|
InitializeHotkeys();
|
|
|
|
if (UISettings::values.theme != old_theme) {
|
|
|
|
UpdateUITheme();
|
|
|
|
}
|
|
|
|
if (UISettings::values.enable_discord_presence != old_discord_presence) {
|
|
|
|
SetDiscordEnabled(UISettings::values.enable_discord_presence);
|
|
|
|
}
|
2019-05-01 14:21:04 -07:00
|
|
|
emit UpdateThemedIcons();
|
2019-05-25 21:39:23 -07:00
|
|
|
|
|
|
|
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
|
|
|
|
if (reload) {
|
2019-05-01 14:21:04 -07:00
|
|
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
2016-01-24 09:34:05 -08:00
|
|
|
}
|
2019-05-25 21:39:23 -07:00
|
|
|
|
|
|
|
config->Save();
|
2020-01-28 14:59:30 -08:00
|
|
|
|
2020-04-10 19:22:50 -07:00
|
|
|
if (UISettings::values.hide_mouse && emulation_running) {
|
|
|
|
setMouseTracking(true);
|
|
|
|
ui.centralwidget->setMouseTracking(true);
|
|
|
|
mouse_hide_timer.start();
|
|
|
|
} else {
|
|
|
|
setMouseTracking(false);
|
|
|
|
ui.centralwidget->setMouseTracking(false);
|
|
|
|
}
|
|
|
|
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
UpdateStatusButtons();
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|
|
|
|
|
2020-08-11 11:57:29 -07:00
|
|
|
void GMainWindow::OnConfigurePerGame() {
|
|
|
|
const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
|
|
|
OpenPerGameConfiguration(title_id, game_path.toStdString());
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file_name) {
|
|
|
|
const auto v_file = Core::GetGameFileFromPath(vfs, file_name);
|
|
|
|
|
|
|
|
ConfigurePerGame dialog(this, title_id);
|
|
|
|
dialog.LoadFromFile(v_file);
|
|
|
|
auto result = dialog.exec();
|
|
|
|
if (result == QDialog::Accepted) {
|
|
|
|
dialog.ApplyConfiguration();
|
|
|
|
|
|
|
|
const auto reload = UISettings::values.is_game_list_reload_pending.exchange(false);
|
|
|
|
if (reload) {
|
|
|
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do not cause the global config to write local settings into the config file
|
|
|
|
Settings::RestoreGlobalState();
|
|
|
|
|
|
|
|
if (!Core::System::GetInstance().IsPoweredOn()) {
|
|
|
|
config->Save();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Settings::RestoreGlobalState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-23 16:28:17 -07:00
|
|
|
void GMainWindow::OnLoadAmiibo() {
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString extensions{QStringLiteral("*.bin")};
|
2018-10-23 16:28:17 -07:00
|
|
|
const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), {}, file_filter);
|
2018-10-24 06:37:29 -07:00
|
|
|
|
|
|
|
if (filename.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-02 11:22:36 -07:00
|
|
|
LoadAmiibo(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::LoadAmiibo(const QString& filename) {
|
2018-10-24 06:37:29 -07:00
|
|
|
Core::System& system{Core::System::GetInstance()};
|
|
|
|
Service::SM::ServiceManager& sm = system.ServiceManager();
|
|
|
|
auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user");
|
|
|
|
if (nfc == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QFile nfc_file{filename};
|
|
|
|
if (!nfc_file.open(QIODevice::ReadOnly)) {
|
|
|
|
QMessageBox::warning(this, tr("Error opening Amiibo data file"),
|
|
|
|
tr("Unable to open Amiibo file \"%1\" for reading.").arg(filename));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const u64 nfc_file_size = nfc_file.size();
|
|
|
|
std::vector<u8> buffer(nfc_file_size);
|
|
|
|
const u64 read_size = nfc_file.read(reinterpret_cast<char*>(buffer.data()), nfc_file_size);
|
|
|
|
if (nfc_file_size != read_size) {
|
|
|
|
QMessageBox::warning(this, tr("Error reading Amiibo data file"),
|
|
|
|
tr("Unable to fully read Amiibo data. Expected to read %1 bytes, but "
|
|
|
|
"was only able to read %2 bytes.")
|
|
|
|
.arg(nfc_file_size)
|
|
|
|
.arg(read_size));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nfc->LoadAmiibo(buffer)) {
|
|
|
|
QMessageBox::warning(this, tr("Error loading Amiibo data"),
|
|
|
|
tr("Unable to load Amiibo data."));
|
2018-10-23 16:28:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-01 19:05:44 -07:00
|
|
|
void GMainWindow::OnOpenYuzuFolder() {
|
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
2020-08-15 05:33:16 -07:00
|
|
|
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::UserDir))));
|
2018-11-01 19:05:44 -07:00
|
|
|
}
|
|
|
|
|
2018-01-14 10:15:45 -08:00
|
|
|
void GMainWindow::OnAbout() {
|
|
|
|
AboutDialog aboutDialog(this);
|
|
|
|
aboutDialog.exec();
|
|
|
|
}
|
|
|
|
|
2017-04-29 19:04:39 -07:00
|
|
|
void GMainWindow::OnToggleFilterBar() {
|
|
|
|
game_list->setFilterVisible(ui.action_Show_Filter_Bar->isChecked());
|
|
|
|
if (ui.action_Show_Filter_Bar->isChecked()) {
|
|
|
|
game_list->setFilterFocus();
|
|
|
|
} else {
|
|
|
|
game_list->clearFilter();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-30 23:16:16 -07:00
|
|
|
void GMainWindow::OnCaptureScreenshot() {
|
|
|
|
OnPauseGame();
|
2020-07-06 20:30:49 -07:00
|
|
|
|
|
|
|
const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
2020-07-07 10:47:08 -07:00
|
|
|
const auto screenshot_path =
|
2020-08-15 05:33:16 -07:00
|
|
|
QString::fromStdString(Common::FS::GetUserPath(Common::FS::UserPath::ScreenshotsDir));
|
2020-07-07 10:47:08 -07:00
|
|
|
const auto date =
|
|
|
|
QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd_hh-mm-ss-zzz"));
|
|
|
|
QString filename = QStringLiteral("%1%2_%3.png")
|
|
|
|
.arg(screenshot_path)
|
|
|
|
.arg(title_id, 16, 16, QLatin1Char{'0'})
|
|
|
|
.arg(date);
|
2020-07-06 20:30:49 -07:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (UISettings::values.enable_screenshot_save_as) {
|
|
|
|
filename = QFileDialog::getSaveFileName(this, tr("Capture Screenshot"), filename,
|
|
|
|
tr("PNG Image (*.png)"));
|
|
|
|
if (filename.isEmpty()) {
|
|
|
|
OnStartGame();
|
|
|
|
return;
|
2019-01-19 19:14:19 -08:00
|
|
|
}
|
2018-08-30 23:16:16 -07:00
|
|
|
}
|
2020-07-06 20:30:49 -07:00
|
|
|
#endif
|
|
|
|
render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, filename);
|
2018-08-30 23:16:16 -07:00
|
|
|
OnStartGame();
|
|
|
|
}
|
|
|
|
|
2020-06-08 14:58:04 -07:00
|
|
|
void GMainWindow::UpdateWindowTitle(const std::string& title_name,
|
|
|
|
const std::string& title_version) {
|
2019-10-04 21:10:04 -07:00
|
|
|
const auto full_name = std::string(Common::g_build_fullname);
|
|
|
|
const auto branch_name = std::string(Common::g_scm_branch);
|
|
|
|
const auto description = std::string(Common::g_scm_desc);
|
|
|
|
const auto build_id = std::string(Common::g_build_id);
|
|
|
|
|
|
|
|
const auto date =
|
|
|
|
QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString();
|
2019-05-08 22:41:33 -07:00
|
|
|
|
2020-06-08 14:58:04 -07:00
|
|
|
if (title_name.empty()) {
|
2019-10-04 21:10:04 -07:00
|
|
|
const auto fmt = std::string(Common::g_title_bar_format_idle);
|
|
|
|
setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt,
|
|
|
|
full_name, branch_name, description,
|
|
|
|
std::string{}, date, build_id)));
|
2019-05-08 22:41:33 -07:00
|
|
|
} else {
|
2019-10-06 12:07:00 -07:00
|
|
|
const auto fmt = std::string(Common::g_title_bar_format_running);
|
2019-10-04 21:10:04 -07:00
|
|
|
setWindowTitle(QString::fromStdString(
|
2020-06-22 06:56:41 -07:00
|
|
|
fmt::format(fmt.empty() ? "yuzu {0}| {3} | {6} | {1}-{2}" : fmt, full_name, branch_name,
|
|
|
|
description, title_name, date, build_id, title_version)));
|
2019-05-08 22:41:33 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-19 14:34:47 -08:00
|
|
|
void GMainWindow::UpdateStatusBar() {
|
|
|
|
if (emu_thread == nullptr) {
|
|
|
|
status_bar_update_timer.stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto results = Core::System::GetInstance().GetAndResetPerfStats();
|
2020-07-09 20:36:38 -07:00
|
|
|
auto& shader_notify = Core::System::GetInstance().GPU().ShaderNotify();
|
|
|
|
const auto shaders_building = shader_notify.GetShadersBuilding();
|
|
|
|
|
|
|
|
if (shaders_building != 0) {
|
|
|
|
shader_building_label->setText(
|
2020-07-27 18:02:08 -07:00
|
|
|
tr("Building: %n shader(s)", "", static_cast<int>(shaders_building)));
|
2020-07-09 20:36:38 -07:00
|
|
|
shader_building_label->setVisible(true);
|
|
|
|
} else {
|
|
|
|
shader_building_label->setVisible(false);
|
|
|
|
}
|
2017-02-19 14:34:47 -08:00
|
|
|
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
if (Settings::values.use_frame_limit.GetValue()) {
|
2018-08-20 16:14:06 -07:00
|
|
|
emu_speed_label->setText(tr("Speed: %1% / %2%")
|
|
|
|
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
.arg(Settings::values.frame_limit.GetValue()));
|
2018-08-20 16:14:06 -07:00
|
|
|
} else {
|
|
|
|
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
|
|
|
|
}
|
2017-02-19 18:56:26 -08:00
|
|
|
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
|
2017-02-19 14:34:47 -08:00
|
|
|
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
|
|
|
|
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
|
2017-02-19 14:34:47 -08:00
|
|
|
game_fps_label->setVisible(true);
|
|
|
|
emu_frametime_label->setVisible(true);
|
|
|
|
}
|
|
|
|
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
void GMainWindow::UpdateStatusButtons() {
|
|
|
|
dock_status_button->setChecked(Settings::values.use_docked_mode);
|
|
|
|
multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
|
|
|
|
Settings::values.use_asynchronous_gpu_emulation.SetValue(
|
|
|
|
Settings::values.use_asynchronous_gpu_emulation.GetValue() ||
|
|
|
|
Settings::values.use_multi_core.GetValue());
|
|
|
|
async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
|
|
|
|
#ifdef HAS_VULKAN
|
|
|
|
renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
|
|
|
|
Settings::RendererBackend::Vulkan);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-04-10 19:22:50 -07:00
|
|
|
void GMainWindow::HideMouseCursor() {
|
|
|
|
if (emu_thread == nullptr || UISettings::values.hide_mouse == false) {
|
|
|
|
mouse_hide_timer.stop();
|
|
|
|
ShowMouseCursor();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
setCursor(QCursor(Qt::BlankCursor));
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::ShowMouseCursor() {
|
|
|
|
unsetCursor();
|
|
|
|
if (emu_thread != nullptr && UISettings::values.hide_mouse) {
|
|
|
|
mouse_hide_timer.start();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::mouseMoveEvent(QMouseEvent* event) {
|
|
|
|
ShowMouseCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::mousePressEvent(QMouseEvent* event) {
|
|
|
|
ShowMouseCursor();
|
|
|
|
}
|
|
|
|
|
2017-04-12 22:18:54 -07:00
|
|
|
void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
|
2017-04-12 22:15:23 -07:00
|
|
|
QMessageBox::StandardButton answer;
|
|
|
|
QString status_message;
|
2018-10-23 16:28:17 -07:00
|
|
|
const QString common_message =
|
|
|
|
tr("The game you are trying to load requires additional files from your Switch to be "
|
|
|
|
"dumped "
|
|
|
|
"before playing.<br/><br/>For more information on dumping these files, please see the "
|
|
|
|
"following wiki page: <a "
|
|
|
|
"href='https://yuzu-emu.org/wiki/"
|
|
|
|
"dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System "
|
|
|
|
"Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to "
|
|
|
|
"quit "
|
|
|
|
"back to the game list? Continuing emulation may result in crashes, corrupted save "
|
|
|
|
"data, or other bugs.");
|
2017-03-08 13:28:30 -08:00
|
|
|
switch (result) {
|
2017-04-12 22:15:23 -07:00
|
|
|
case Core::System::ResultStatus::ErrorSystemFiles: {
|
2019-07-07 07:50:06 -07:00
|
|
|
QString message;
|
|
|
|
if (details.empty()) {
|
|
|
|
message =
|
|
|
|
tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message);
|
2017-06-02 14:03:38 -07:00
|
|
|
} else {
|
2019-07-07 07:50:06 -07:00
|
|
|
message = tr("yuzu was unable to locate a Switch system archive: %1. %2")
|
|
|
|
.arg(QString::fromStdString(details), common_message);
|
2017-06-02 14:03:38 -07:00
|
|
|
}
|
2017-04-12 22:15:23 -07:00
|
|
|
|
|
|
|
answer = QMessageBox::question(this, tr("System Archive Not Found"), message,
|
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
2019-05-24 16:44:06 -07:00
|
|
|
status_message = tr("System Archive Missing");
|
2017-03-08 13:28:30 -08:00
|
|
|
break;
|
2017-04-12 22:15:23 -07:00
|
|
|
}
|
2017-03-08 13:28:30 -08:00
|
|
|
|
2017-04-12 22:15:23 -07:00
|
|
|
case Core::System::ResultStatus::ErrorSharedFont: {
|
2019-07-07 07:50:06 -07:00
|
|
|
const QString message =
|
|
|
|
tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message);
|
2017-04-12 22:15:23 -07:00
|
|
|
answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
|
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
2019-05-24 16:44:06 -07:00
|
|
|
status_message = tr("Shared Font Missing");
|
2017-03-08 13:28:30 -08:00
|
|
|
break;
|
2017-04-12 22:15:23 -07:00
|
|
|
}
|
2017-03-08 13:28:30 -08:00
|
|
|
|
2017-03-08 17:21:31 -08:00
|
|
|
default:
|
2017-04-12 22:15:23 -07:00
|
|
|
answer = QMessageBox::question(
|
|
|
|
this, tr("Fatal Error"),
|
2018-01-13 15:49:16 -08:00
|
|
|
tr("yuzu has encountered a fatal error, please see the log for more details. "
|
2017-04-12 22:15:23 -07:00
|
|
|
"For more information on accessing the log, please see the following page: "
|
2018-10-23 16:28:17 -07:00
|
|
|
"<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
|
|
|
|
"to "
|
|
|
|
"Upload the Log File</a>.<br/><br/>Would you like to quit back to the game "
|
|
|
|
"list? "
|
|
|
|
"Continuing emulation may result in crashes, corrupted save data, or other "
|
|
|
|
"bugs."),
|
2017-04-12 22:15:23 -07:00
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
2019-05-24 16:44:06 -07:00
|
|
|
status_message = tr("Fatal Error encountered");
|
2017-03-08 13:28:30 -08:00
|
|
|
break;
|
|
|
|
}
|
2017-04-12 22:15:23 -07:00
|
|
|
|
|
|
|
if (answer == QMessageBox::Yes) {
|
2017-06-02 14:03:38 -07:00
|
|
|
if (emu_thread) {
|
2017-04-12 22:15:23 -07:00
|
|
|
ShutdownGame();
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
|
|
|
|
Settings::RestoreGlobalState();
|
|
|
|
UpdateStatusButtons();
|
2017-06-02 14:03:38 -07:00
|
|
|
}
|
2017-04-12 22:15:23 -07:00
|
|
|
} else {
|
2017-06-02 14:03:38 -07:00
|
|
|
// Only show the message if the game is still running.
|
|
|
|
if (emu_thread) {
|
2018-01-16 08:32:27 -08:00
|
|
|
emu_thread->SetRunning(true);
|
2017-06-02 14:03:38 -07:00
|
|
|
message_label->setText(status_message);
|
|
|
|
}
|
2017-04-12 22:15:23 -07:00
|
|
|
}
|
2017-03-08 13:28:30 -08:00
|
|
|
}
|
|
|
|
|
2018-09-29 08:48:51 -07:00
|
|
|
void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
|
|
|
|
if (behavior == ReinitializeKeyBehavior::Warning) {
|
2018-09-23 18:35:32 -07:00
|
|
|
const auto res = QMessageBox::information(
|
|
|
|
this, tr("Confirm Key Rederivation"),
|
2020-07-09 20:36:38 -07:00
|
|
|
tr("You are about to force rederive all of your keys. \nIf you do not know what "
|
|
|
|
"this "
|
|
|
|
"means or what you are doing, \nthis is a potentially destructive action. "
|
|
|
|
"\nPlease "
|
|
|
|
"make sure this is what you want \nand optionally make backups.\n\nThis will "
|
|
|
|
"delete "
|
2019-01-16 23:01:00 -08:00
|
|
|
"your autogenerated key files and re-run the key derivation module."),
|
2018-09-23 18:35:32 -07:00
|
|
|
QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel});
|
|
|
|
|
|
|
|
if (res == QMessageBox::Cancel)
|
|
|
|
return;
|
|
|
|
|
2020-08-15 05:33:16 -07:00
|
|
|
Common::FS::Delete(Common::FS::GetUserPath(Common::FS::UserPath::KeysDir) +
|
|
|
|
"prod.keys_autogenerated");
|
|
|
|
Common::FS::Delete(Common::FS::GetUserPath(Common::FS::UserPath::KeysDir) +
|
|
|
|
"console.keys_autogenerated");
|
|
|
|
Common::FS::Delete(Common::FS::GetUserPath(Common::FS::UserPath::KeysDir) +
|
|
|
|
"title.keys_autogenerated");
|
2018-09-23 18:35:32 -07:00
|
|
|
}
|
|
|
|
|
2020-06-30 21:28:49 -07:00
|
|
|
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
|
2018-09-23 18:35:32 -07:00
|
|
|
if (keys.BaseDeriveNecessary()) {
|
|
|
|
Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory(
|
2020-08-15 05:33:16 -07:00
|
|
|
Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), FileSys::Mode::Read)};
|
2018-09-23 18:35:32 -07:00
|
|
|
|
2018-09-29 08:48:51 -07:00
|
|
|
const auto function = [this, &keys, &pdm] {
|
2018-09-23 18:35:32 -07:00
|
|
|
keys.PopulateFromPartitionData(pdm);
|
2019-04-22 14:56:56 -07:00
|
|
|
Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
|
2018-09-23 18:35:32 -07:00
|
|
|
keys.DeriveETicket(pdm);
|
|
|
|
};
|
|
|
|
|
2018-09-29 08:48:51 -07:00
|
|
|
QString errors;
|
2019-05-24 16:44:06 -07:00
|
|
|
if (!pdm.HasFuses()) {
|
2020-04-13 17:56:22 -07:00
|
|
|
errors += tr("Missing fuses");
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
|
|
|
if (!pdm.HasBoot0()) {
|
2020-04-13 17:56:22 -07:00
|
|
|
errors += tr(" - Missing BOOT0");
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
|
|
|
if (!pdm.HasPackage2()) {
|
2020-04-13 17:56:22 -07:00
|
|
|
errors += tr(" - Missing BCPKG2-1-Normal-Main");
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
|
|
|
if (!pdm.HasProdInfo()) {
|
2020-04-13 17:56:22 -07:00
|
|
|
errors += tr(" - Missing PRODINFO");
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
2018-09-29 08:48:51 -07:00
|
|
|
if (!errors.isEmpty()) {
|
2018-09-23 18:35:32 -07:00
|
|
|
QMessageBox::warning(
|
2020-04-13 17:56:22 -07:00
|
|
|
this, tr("Derivation Components Missing"),
|
|
|
|
tr("Components are missing that may hinder key derivation from completing. "
|
|
|
|
"<br>Please follow <a href='https://yuzu-emu.org/help/quickstart/'>the yuzu "
|
|
|
|
"quickstart guide</a> to get all your keys and "
|
|
|
|
"games.<br><br><small>(%1)</small>")
|
|
|
|
.arg(errors));
|
2018-09-23 18:35:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
QProgressDialog prog;
|
|
|
|
prog.setRange(0, 0);
|
|
|
|
prog.setLabelText(tr("Deriving keys...\nThis may take up to a minute depending \non your "
|
|
|
|
"system's performance."));
|
|
|
|
prog.setWindowTitle(tr("Deriving Keys"));
|
|
|
|
|
|
|
|
prog.show();
|
|
|
|
|
|
|
|
auto future = QtConcurrent::run(function);
|
|
|
|
while (!future.isFinished()) {
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
prog.close();
|
|
|
|
}
|
|
|
|
|
2019-04-22 14:56:56 -07:00
|
|
|
Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
|
2018-09-23 18:35:32 -07:00
|
|
|
|
2018-09-29 08:48:51 -07:00
|
|
|
if (behavior == ReinitializeKeyBehavior::Warning) {
|
2019-05-01 14:21:04 -07:00
|
|
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
2018-09-23 18:35:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-04 09:40:53 -08:00
|
|
|
std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed,
|
|
|
|
u64 program_id) {
|
2018-10-17 15:27:23 -07:00
|
|
|
const auto dlc_entries =
|
|
|
|
installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
2019-03-04 09:40:53 -08:00
|
|
|
std::vector<FileSys::ContentProviderEntry> dlc_match;
|
2018-10-17 15:27:23 -07:00
|
|
|
dlc_match.reserve(dlc_entries.size());
|
|
|
|
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
|
2019-03-04 09:40:53 -08:00
|
|
|
[&program_id, &installed](const FileSys::ContentProviderEntry& entry) {
|
2018-10-17 15:27:23 -07:00
|
|
|
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == program_id &&
|
|
|
|
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
|
|
|
|
});
|
|
|
|
|
|
|
|
std::vector<u64> romfs_tids;
|
|
|
|
romfs_tids.push_back(program_id);
|
2019-05-24 16:44:06 -07:00
|
|
|
for (const auto& entry : dlc_match) {
|
2018-10-17 15:27:23 -07:00
|
|
|
romfs_tids.push_back(entry.title_id);
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
2018-10-17 15:27:23 -07:00
|
|
|
|
|
|
|
if (romfs_tids.size() > 1) {
|
2019-05-24 16:44:06 -07:00
|
|
|
QStringList list{QStringLiteral("Base")};
|
|
|
|
for (std::size_t i = 1; i < romfs_tids.size(); ++i) {
|
2018-10-17 15:27:23 -07:00
|
|
|
list.push_back(QStringLiteral("DLC %1").arg(romfs_tids[i] & 0x7FF));
|
2019-05-24 16:44:06 -07:00
|
|
|
}
|
2018-10-17 15:27:23 -07:00
|
|
|
|
|
|
|
bool ok;
|
|
|
|
const auto res = QInputDialog::getItem(
|
|
|
|
this, tr("Select RomFS Dump Target"),
|
|
|
|
tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
|
|
|
|
if (!ok) {
|
2018-10-29 21:03:25 -07:00
|
|
|
return {};
|
2018-10-17 15:27:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return romfs_tids[list.indexOf(res)];
|
|
|
|
}
|
|
|
|
|
|
|
|
return program_id;
|
|
|
|
}
|
|
|
|
|
2016-01-10 04:31:20 -08:00
|
|
|
bool GMainWindow::ConfirmClose() {
|
2016-01-24 12:54:04 -08:00
|
|
|
if (emu_thread == nullptr || !UISettings::values.confirm_before_closing)
|
2016-01-13 09:40:41 -08:00
|
|
|
return true;
|
2016-01-10 04:31:20 -08:00
|
|
|
|
2017-04-12 22:15:23 -07:00
|
|
|
QMessageBox::StandardButton answer =
|
2018-01-13 15:49:16 -08:00
|
|
|
QMessageBox::question(this, tr("yuzu"), tr("Are you sure you want to close yuzu?"),
|
2017-03-08 17:21:31 -08:00
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
|
|
|
return answer != QMessageBox::No;
|
2016-01-10 04:31:20 -08:00
|
|
|
}
|
|
|
|
|
2015-07-28 09:43:18 -07:00
|
|
|
void GMainWindow::closeEvent(QCloseEvent* event) {
|
2016-01-10 04:31:20 -08:00
|
|
|
if (!ConfirmClose()) {
|
|
|
|
event->ignore();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-12 11:57:15 -08:00
|
|
|
if (!ui.action_Fullscreen->isChecked()) {
|
2018-04-14 04:05:47 -07:00
|
|
|
UISettings::values.geometry = saveGeometry();
|
|
|
|
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
|
|
|
|
}
|
2016-01-24 12:23:55 -08:00
|
|
|
UISettings::values.state = saveState();
|
2016-04-28 17:17:31 -07:00
|
|
|
#if MICROPROFILE_ENABLED
|
2016-01-24 12:23:55 -08:00
|
|
|
UISettings::values.microprofile_geometry = microProfileDialog->saveGeometry();
|
|
|
|
UISettings::values.microprofile_visible = microProfileDialog->isVisible();
|
2016-04-28 17:17:31 -07:00
|
|
|
#endif
|
2016-01-24 12:23:55 -08:00
|
|
|
UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked();
|
2018-01-16 06:50:33 -08:00
|
|
|
UISettings::values.fullscreen = ui.action_Fullscreen->isChecked();
|
2017-02-18 01:11:57 -08:00
|
|
|
UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked();
|
2017-04-29 19:04:39 -07:00
|
|
|
UISettings::values.show_filter_bar = ui.action_Show_Filter_Bar->isChecked();
|
2017-02-18 12:09:14 -08:00
|
|
|
UISettings::values.show_status_bar = ui.action_Show_Status_Bar->isChecked();
|
2016-01-24 12:23:55 -08:00
|
|
|
UISettings::values.first_start = false;
|
2015-09-07 18:11:21 -07:00
|
|
|
|
2016-01-24 12:23:55 -08:00
|
|
|
game_list->SaveInterfaceLayout();
|
2018-08-06 21:43:07 -07:00
|
|
|
hotkey_registry.SaveHotkeys();
|
2014-03-31 19:26:50 -07:00
|
|
|
|
2015-05-12 20:14:24 -07:00
|
|
|
// Shutdown session if the emu thread is active...
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
if (emu_thread != nullptr) {
|
2015-05-12 20:14:24 -07:00
|
|
|
ShutdownGame();
|
2015-05-01 13:53:16 -07:00
|
|
|
|
configuration: implement per-game configurations (#4098)
* Switch game settings to use a pointer
In order to add full per-game settings, we need to be able to tell yuzu to switch
to using either the global or game configuration. Using a pointer makes it easier
to switch.
* configuration: add new UI without changing existing funcitonality
The new UI also adds General, System, Graphics, Advanced Graphics,
and Audio tabs, but as yet they do nothing. This commit keeps yuzu
to the same functionality as originally branched.
* configuration: Rename files
These weren't included in the last commit. Now they are.
* configuration: setup global configuration checkbox
Global config checkbox now enables/disables the appropriate tabs in the game
properties dialog. The use global configuration setting is now saved to the
config, defaulting to true. This also addresses some changes requested in the PR.
* configuration: swap to per-game config memory for properties dialog
Does not set memory going in-game. Swaps to game values when opening the
properties dialog, then swaps back when closing it. Uses a `memcpy` to swap.
Also implements saving config files, limited to certain groups of configurations
so as to not risk setting unsafe configurations.
* configuration: change config interfaces to use config-specific pointers
When a game is booted, we need to be able to open the configuration dialogs
without changing the settings pointer in the game's emualtion. A new pointer
specific to just the configuration dialogs can be used to separate changes
to just those config dialogs without affecting the emulation.
* configuration: boot a game using per-game settings
Swaps values where needed to boot a game.
* configuration: user correct config during emulation
Creates a new pointer specifically for modifying the configuration while
emulation is in progress. Both the regular configuration dialog and the game
properties dialog now use the pointer Settings::config_values to focus edits to
the correct struct.
* settings: split Settings::values into two different structs
By splitting the settings into two mutually exclusive structs, it becomes easier,
as a developer, to determine how to use the Settings structs after per-game
configurations is merged. Other benefits include only duplicating the required
settings in memory.
* settings: move use_docked_mode to Controls group
`use_docked_mode` is set in the input settings and cannot be accessed from the
system settings. Grouping it with system settings causes it to be saved with
per-game settings, which may make transferring configs more difficult later on,
especially since docked mode cannot be set from within the game properties
dialog.
* configuration: Fix the other yuzu executables and a regression
In main.cpp, we have to get the title ID before the ROM is loaded, else the
renderer will reflect only the global settings and now the user's game specific
settings.
* settings: use a template to duplicate memory for each setting
Replaces the type of each variable in the Settings::Values struct with a new
class that allows basic data reading and writing. The new struct
Settings::Setting duplicates the data in memory and can manage global overrides
per each setting.
* configuration: correct add-ons config and swap settings when apropriate
Any add-ons interaction happens directly through the global values struct.
Swapping bewteen structs now also includes copying the necessary global configs
that cannot be changed nor saved in per-game settings. General and System config
menus now update based on whether it is viewing the global or per-game settings.
* settings: restore old values struct
No longer needed with the Settings::Setting class template.
* configuration: implement hierarchical game properties dialog
This sets the apropriate global or local data in each setting.
* clang format
* clang format take 2
can the docker container save this?
* address comments and style issues
* config: read and write settings with global awareness
Adds new functions to read and write settings while keeping the global state in
focus. Files now generated per-game are much smaller since often they only need
address the global state.
* settings: restore global state when necessary
Upon closing a game or the game properties dialog, we need to restore all global
settings to the original global state so that we can properly open the
configuration dialog or boot a different game.
* configuration: guard setting values incorrectly
This disables setting values while a game is running if the setting is
overwritten by a per game setting.
* config: don't write local settings in the global config
Simple guards to prevent writing the wrong settings in the wrong files.
* configuration: add comments, assume less, and clang format
No longer assumes that a disabled UI element means the global state is turned
off, instead opting to directly answer that question. Still however assumes a
game is running if it is in that state.
* configuration: fix a logic error
Should not be negated
* restore settings' global state regardless of accept/cancel
Fixes loading a properties dialog and causing the global config dialog to show
local settings.
* fix more logic errors
Fixed the frame limit would set the global setting from the game properties
dialog. Also strengthened the Settings::Setting member variables and simplified
the logic in config reading (ReadSettingGlobal).
* fix another logic error
In my efforts to guard RestoreGlobalState, I accidentally negated the IsPowered
condition.
* configure_audio: set toggle_stretched_audio to tristate
* fixed custom rtc and rng seed overwriting the global value
* clang format
* rebased
* clang format take 4
* address my own review
Basically revert unintended changes
* settings: literal instead of casting
"No need to cast, use 1U instead"
Thanks, Morph!
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
* Revert "settings: literal instead of casting
"
This reverts commit 95e992a87c898f3e882ffdb415bb0ef9f80f613f.
* main: fix status buttons reporting wrong settings after stop emulation
* settings: Log UseDockedMode in the Controls group
This should have happened when use_docked_mode was moved over to the controls group
internally. This just reflects this in the log.
* main: load settings if the file has a title id
In other words, don't exit if the loader has trouble getting a title id.
* use a zero
* settings: initalize resolution factor with constructor instead of casting
* Revert "settings: initalize resolution factor with constructor instead of casting"
This reverts commit 54c35ecb46a29953842614620f9b7de1aa9d5dc8.
* configure_graphics: guard device selector when Vulkan is global
Prevents the user from editing the device selector if Vulkan is the global
renderer backend. Also resets the vulkan_device variable when the users
switches back-and-forth between global and Vulkan.
* address reviewer concerns
Changes function variables to const wherever they don't need to be changed. Sets Settings::Setting to final as it should not be inherited from. Sets ConfigurationShared::use_global_text to static.
Co-Authored-By: VolcaEM <volcaem@users.noreply.github.com>
* main: load per-game settings after LoadROM
This prevents `Restart Emulation` from restoring the global settings *after* the per-game settings were applied. Thanks to BSoDGamingYT for finding this bug.
* Revert "main: load per-game settings after LoadROM"
This reverts commit 9d0d48c52d2dcf3bfb1806cc8fa7d5a271a8a804.
* main: only restore global settings when necessary
Loading the per-game settings cannot happen after the ROM is loaded, so we have to specify when to restore the global state. Again thanks to BSoD for finding the bug.
* configuration_shared: address reviewer concerns except operator overrides
Dropping operator override usage in next commit.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
* settings: Drop operator overrides from Setting template
Requires using GetValue and SetValue explicitly. Also reverts a change that broke title ID formatting in the game properties dialog.
* complete rebase
* configuration_shared: translate "Use global configuration"
Uses ConfigurePerGame to do so, since its usage, at least as of now, corresponds with ConfigurationShared.
* configure_per_game: address reviewer concern
As far as I understand, it prevents the program from unnecessarily copying strings.
Co-Authored-By: LC <lioncash@users.noreply.github.com>
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>
Co-authored-by: VolcaEM <volcaem@users.noreply.github.com>
Co-authored-by: LC <lioncash@users.noreply.github.com>
2020-07-09 19:42:09 -07:00
|
|
|
Settings::RestoreGlobalState();
|
|
|
|
UpdateStatusButtons();
|
|
|
|
}
|
|
|
|
|
2014-03-31 19:26:50 -07:00
|
|
|
render_window->close();
|
|
|
|
|
|
|
|
QWidget::closeEvent(event);
|
|
|
|
}
|
|
|
|
|
2020-02-17 12:49:52 -08:00
|
|
|
static bool IsSingleFileDropEvent(const QMimeData* mime) {
|
|
|
|
return mime->hasUrls() && mime->urls().length() == 1;
|
2020-01-21 11:40:53 -08:00
|
|
|
}
|
|
|
|
|
2020-02-17 12:49:52 -08:00
|
|
|
void GMainWindow::AcceptDropEvent(QDropEvent* event) {
|
|
|
|
if (IsSingleFileDropEvent(event->mimeData())) {
|
|
|
|
event->setDropAction(Qt::DropAction::LinkAction);
|
|
|
|
event->accept();
|
2020-01-21 11:40:53 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-17 12:49:52 -08:00
|
|
|
bool GMainWindow::DropAction(QDropEvent* event) {
|
|
|
|
if (!IsSingleFileDropEvent(event->mimeData())) {
|
|
|
|
return false;
|
2019-11-02 11:22:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const QMimeData* mime_data = event->mimeData();
|
2020-02-17 12:49:52 -08:00
|
|
|
const QString& filename = mime_data->urls().at(0).toLocalFile();
|
2019-11-02 11:22:36 -07:00
|
|
|
|
|
|
|
if (emulation_running && QFileInfo(filename).suffix() == QStringLiteral("bin")) {
|
2020-02-17 12:49:52 -08:00
|
|
|
// Amiibo
|
2019-11-02 11:22:36 -07:00
|
|
|
LoadAmiibo(filename);
|
|
|
|
} else {
|
2020-02-17 12:49:52 -08:00
|
|
|
// Game
|
2019-11-02 11:22:36 -07:00
|
|
|
if (ConfirmChangeGame()) {
|
|
|
|
BootGame(filename);
|
|
|
|
}
|
2017-02-15 19:23:30 -08:00
|
|
|
}
|
2020-02-17 12:49:52 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::dropEvent(QDropEvent* event) {
|
|
|
|
DropAction(event);
|
2017-02-15 19:23:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::dragEnterEvent(QDragEnterEvent* event) {
|
2020-02-17 12:49:52 -08:00
|
|
|
AcceptDropEvent(event);
|
2017-02-15 19:23:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::dragMoveEvent(QDragMoveEvent* event) {
|
2020-02-17 12:49:52 -08:00
|
|
|
AcceptDropEvent(event);
|
2017-02-15 19:23:30 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GMainWindow::ConfirmChangeGame() {
|
|
|
|
if (emu_thread == nullptr)
|
|
|
|
return true;
|
|
|
|
|
2019-09-22 07:02:07 -07:00
|
|
|
const auto answer = QMessageBox::question(
|
2018-01-13 15:49:16 -08:00
|
|
|
this, tr("yuzu"),
|
2017-02-15 19:23:30 -08:00
|
|
|
tr("Are you sure you want to stop the emulation? Any unsaved progress will be lost."),
|
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
|
|
|
return answer != QMessageBox::No;
|
|
|
|
}
|
|
|
|
|
2019-09-21 19:46:53 -07:00
|
|
|
bool GMainWindow::ConfirmForceLockedExit() {
|
|
|
|
if (emu_thread == nullptr)
|
|
|
|
return true;
|
|
|
|
|
2019-09-22 07:02:07 -07:00
|
|
|
const auto answer =
|
2019-09-21 19:46:53 -07:00
|
|
|
QMessageBox::question(this, tr("yuzu"),
|
|
|
|
tr("The currently running application has requested yuzu to not "
|
|
|
|
"exit.\n\nWould you like to bypass this and exit anyway?"),
|
|
|
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
|
|
|
return answer != QMessageBox::No;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::RequestGameExit() {
|
|
|
|
auto& sm{Core::System::GetInstance().ServiceManager()};
|
|
|
|
auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
|
|
|
|
auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
|
|
|
|
bool has_signalled = false;
|
|
|
|
|
|
|
|
if (applet_oe != nullptr) {
|
|
|
|
applet_oe->GetMessageQueue()->RequestExit();
|
|
|
|
has_signalled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (applet_ae != nullptr && !has_signalled) {
|
|
|
|
applet_ae->GetMessageQueue()->RequestExit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-29 19:04:39 -07:00
|
|
|
void GMainWindow::filterBarSetChecked(bool state) {
|
|
|
|
ui.action_Show_Filter_Bar->setChecked(state);
|
|
|
|
emit(OnToggleFilterBar());
|
|
|
|
}
|
|
|
|
|
2018-03-30 02:50:10 -07:00
|
|
|
void GMainWindow::UpdateUITheme() {
|
2019-05-24 16:44:06 -07:00
|
|
|
const QString default_icons = QStringLiteral(":/icons/default");
|
|
|
|
const QString& current_theme = UISettings::values.theme;
|
|
|
|
const bool is_default_theme = current_theme == QString::fromUtf8(UISettings::themes[0].second);
|
2018-03-30 02:50:10 -07:00
|
|
|
QStringList theme_paths(default_theme_paths);
|
2019-05-24 16:44:06 -07:00
|
|
|
|
|
|
|
if (is_default_theme || current_theme.isEmpty()) {
|
2020-01-28 14:59:30 -08:00
|
|
|
const QString theme_uri(QStringLiteral(":default/style.qss"));
|
|
|
|
QFile f(theme_uri);
|
|
|
|
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
|
|
|
QTextStream ts(&f);
|
|
|
|
qApp->setStyleSheet(ts.readAll());
|
|
|
|
setStyleSheet(ts.readAll());
|
|
|
|
} else {
|
|
|
|
qApp->setStyleSheet({});
|
|
|
|
setStyleSheet({});
|
|
|
|
}
|
2019-05-24 16:44:06 -07:00
|
|
|
theme_paths.append(default_icons);
|
|
|
|
QIcon::setThemeName(default_icons);
|
|
|
|
} else {
|
|
|
|
const QString theme_uri(QLatin1Char{':'} + current_theme + QStringLiteral("/style.qss"));
|
2018-03-30 02:50:10 -07:00
|
|
|
QFile f(theme_uri);
|
2018-08-06 11:12:57 -07:00
|
|
|
if (f.open(QFile::ReadOnly | QFile::Text)) {
|
2018-03-30 02:50:10 -07:00
|
|
|
QTextStream ts(&f);
|
|
|
|
qApp->setStyleSheet(ts.readAll());
|
2019-05-24 16:44:06 -07:00
|
|
|
setStyleSheet(ts.readAll());
|
2018-08-06 11:12:57 -07:00
|
|
|
} else {
|
|
|
|
LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found");
|
2018-03-30 02:50:10 -07:00
|
|
|
}
|
2019-05-24 16:44:06 -07:00
|
|
|
|
|
|
|
const QString theme_name = QStringLiteral(":/icons/") + current_theme;
|
|
|
|
theme_paths.append({default_icons, theme_name});
|
|
|
|
QIcon::setThemeName(theme_name);
|
2018-03-30 02:50:10 -07:00
|
|
|
}
|
2019-05-24 16:44:06 -07:00
|
|
|
|
2018-03-30 02:50:10 -07:00
|
|
|
QIcon::setThemeSearchPaths(theme_paths);
|
|
|
|
}
|
|
|
|
|
2020-01-25 15:26:07 -08:00
|
|
|
void GMainWindow::LoadTranslation() {
|
|
|
|
// If the selected language is English, no need to install any translation
|
|
|
|
if (UISettings::values.language == QStringLiteral("en")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool loaded;
|
|
|
|
|
|
|
|
if (UISettings::values.language.isEmpty()) {
|
|
|
|
// If the selected language is empty, use system locale
|
|
|
|
loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/"));
|
|
|
|
} else {
|
|
|
|
// Otherwise load from the specified file
|
|
|
|
loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loaded) {
|
|
|
|
qApp->installTranslator(&translator);
|
|
|
|
} else {
|
|
|
|
UISettings::values.language = QStringLiteral("en");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GMainWindow::OnLanguageChanged(const QString& locale) {
|
|
|
|
if (UISettings::values.language != QStringLiteral("en")) {
|
|
|
|
qApp->removeTranslator(&translator);
|
|
|
|
}
|
|
|
|
|
|
|
|
UISettings::values.language = locale;
|
|
|
|
LoadTranslation();
|
|
|
|
ui.retranslateUi(this);
|
|
|
|
UpdateWindowTitle();
|
|
|
|
|
|
|
|
if (emulation_running)
|
|
|
|
ui.action_Start->setText(tr("Continue"));
|
|
|
|
}
|
|
|
|
|
2018-10-13 07:10:27 -07:00
|
|
|
void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
|
2018-09-16 11:05:51 -07:00
|
|
|
#ifdef USE_DISCORD_PRESENCE
|
|
|
|
if (state) {
|
|
|
|
discord_rpc = std::make_unique<DiscordRPC::DiscordImpl>();
|
|
|
|
} else {
|
|
|
|
discord_rpc = std::make_unique<DiscordRPC::NullImpl>();
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
discord_rpc = std::make_unique<DiscordRPC::NullImpl>();
|
|
|
|
#endif
|
|
|
|
discord_rpc->Update();
|
|
|
|
}
|
|
|
|
|
2014-03-31 19:26:50 -07:00
|
|
|
#ifdef main
|
|
|
|
#undef main
|
|
|
|
#endif
|
|
|
|
|
2015-07-28 09:43:18 -07:00
|
|
|
int main(int argc, char* argv[]) {
|
2018-09-16 11:05:51 -07:00
|
|
|
Common::DetachedTasks detached_tasks;
|
2015-08-17 14:25:21 -07:00
|
|
|
MicroProfileOnThreadCreate("Frontend");
|
2016-09-17 17:38:01 -07:00
|
|
|
SCOPE_EXIT({ MicroProfileShutdown(); });
|
2015-08-17 14:25:21 -07:00
|
|
|
|
2015-07-26 08:13:02 -07:00
|
|
|
// Init settings params
|
2019-05-24 16:44:06 -07:00
|
|
|
QCoreApplication::setOrganizationName(QStringLiteral("yuzu team"));
|
|
|
|
QCoreApplication::setApplicationName(QStringLiteral("yuzu"));
|
2015-07-26 08:13:02 -07:00
|
|
|
|
2019-08-11 03:28:07 -07:00
|
|
|
#ifdef __APPLE__
|
2019-09-04 18:40:49 -07:00
|
|
|
// If you start a bundle (binary) on OSX without the Terminal, the working directory is "/".
|
2020-07-09 20:36:38 -07:00
|
|
|
// But since we require the working directory to be the executable path for the location of
|
|
|
|
// the user folder in the Qt Frontend, we need to cd into that working directory
|
2020-08-15 05:33:16 -07:00
|
|
|
const std::string bin_path = Common::FS::GetBundleDirectory() + DIR_SEP + "..";
|
2019-08-11 03:28:07 -07:00
|
|
|
chdir(bin_path.c_str());
|
|
|
|
#endif
|
|
|
|
|
2019-01-11 20:06:34 -08:00
|
|
|
// Enables the core to make the qt created contexts current on std::threads
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
2014-03-31 19:26:50 -07:00
|
|
|
QApplication app(argc, argv);
|
2014-12-06 14:00:08 -08:00
|
|
|
|
2016-09-17 17:38:01 -07:00
|
|
|
// Qt changes the locale and causes issues in float conversion using std::to_string() when
|
|
|
|
// generating shaders
|
2016-03-06 05:04:47 -08:00
|
|
|
setlocale(LC_ALL, "C");
|
|
|
|
|
2014-03-31 19:26:50 -07:00
|
|
|
GMainWindow main_window;
|
2014-12-06 14:00:08 -08:00
|
|
|
// After settings have been loaded by GMainWindow, apply the filter
|
2014-03-31 19:26:50 -07:00
|
|
|
main_window.show();
|
2018-07-10 03:02:14 -07:00
|
|
|
|
2019-09-26 05:54:31 -07:00
|
|
|
QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window,
|
|
|
|
&GMainWindow::OnAppFocusStateChanged);
|
|
|
|
|
2018-09-16 11:05:51 -07:00
|
|
|
int result = app.exec();
|
|
|
|
detached_tasks.WaitForAllTasks();
|
|
|
|
return result;
|
2014-03-31 19:26:50 -07:00
|
|
|
}
|